2002-12-04 Marcus Brinkmann <marcus@g10code.de>

* gpgme.h: Add prototype for gpgme_get_key.
	* key.c (gpgme_get_key): New function.
	* verify.c (gpgme_get_sig_key): Rewrite using gpgme_get_key.

	* gpgme.h: Add prototypes for new interfaces
	gpgme_key_sig_get_string_attr and gpgme_key_get_ulong_attr.
	(enum GpgmeAttr): New attribute GPGME_ATTR_SIG_CLASS.
	* gpgme.c (gpgme_set_keylist_mode): Allow GPGME_KEYLIST_MODE_SIGS.
	* key.h (struct certsig_s): New members ALGO, NAME_PART,
	EMAIL_PART, COMMENT_PART, NAME, SIG_STAT and SIG_CLASS.

	* conversion.c (_gpgme_decode_c_string): Add new parameter LEN.
	Use that to determine if allocation is desired or not.
	* util.h: Adjust prototype of _gpgme_decode_c_string.
	* keylist.c (keylist_colon_handler): Adjust caller of
	_gpgme_decode_c_string.

	* key.h (struct gpgme_key_s): New member last_uid.
	* key.c (_gpgme_key_append_name): Rewritten using
	_gpgme_decode_c_string and the last_uid pointer.
	(my_isdigit): Macro removed.
	(ALLOC_CHUNK): Likewise.
	* keylist.c (set_userid_flags): Use last_uid member of KEY.

	* context.h (struct user_id_s): New member last_certsig.
	* key.h: Add prototype for _gpgme_key_add_certsig.
	* key.c (_gpgme_key_add_certsig): New function.
	(set_user_id_part): Move function before _gpgme_key_add_certsig.
	(parse_user_id): Change first argument to SRC, add new arguments
	NAME, EMAIL and COMMENT.  Change code to use these arguments
	instead going through UID.  Move function before
	_gpgme_add_certsig.
	(parse_x509_user_id): Likewise.
	(_gpgme_key_append_name): Adjust arguments to parse_x509_user_id
	and parse_user_id invocation.
	(one_certsig_as_xml): New function.
	(one_uid_as_xml): Print signatures.
	* context.h (struct gpgme_context_s): New member TMP_UID.
	* keylist.c (keylist_colon_handler): Rewritten, implement "sig"
	record entries.

	* key.c (get_certsig): New function.
	(gpgme_key_sig_get_string_attr): Likewise.
	(gpgme_key_sig_get_ulong_attr): Likewise.

	* keylist.c: Include <ctype.h>.
	(my_isdigit): Macro removed.
	(set_mainkey_trust_info): Use isdigit, not my_isdigit.
	(set_userid_flags): Likewise.
	(set_subkey_trust_info): Likewise.
	(set_ownertrust): Likewise.
	(finish_key): Move function up a bit and remove prototype.

	* rungpg.c (gpg_keylist_ext): Correct precedence of signature
	listing mode.
	(gpg_keylist_ext): Implement signature listing mode.
This commit is contained in:
Marcus Brinkmann 2002-12-04 16:28:34 +00:00
parent 7394638cdb
commit 1b495c5140
12 changed files with 1202 additions and 771 deletions

11
NEWS
View File

@ -1,6 +1,12 @@
Noteworthy changes in version 0.4.0 (unreleased) Noteworthy changes in version 0.4.0 (unreleased)
------------------------------------------------ ------------------------------------------------
* Supports signatures of user IDs in keys via the new
GPGME_KEYLIST_MODE_SIGS keylist mode and the
gpgme_key_sig_get_string_attr and gpgme_key_sig_get_ulong_attr
interfaces. The XML info about a key also includes the signatures
if available.
* New data object interface, which is more flexible and transparent. * New data object interface, which is more flexible and transparent.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -23,6 +29,11 @@ gpgme_op_verify CHANGED: Take different data objects for
gpgme_op_verify_start CHANGED: See gpgme_op_verify. gpgme_op_verify_start CHANGED: See gpgme_op_verify.
gpgme_check_engine REMOVED: Deprecated since 0.3.0. gpgme_check_engine REMOVED: Deprecated since 0.3.0.
gpgme_op_genkey CHANGED: New parameter FPR. gpgme_op_genkey CHANGED: New parameter FPR.
GPGME_KEYLIST_MODE_SIGS NEW
gpgme_key_sig_get_string_attr NEW
gpgme_key_sig_get_ulong_attr NEW
gpgme_get_key NEW
GPGME_ATTR_SIG_CLASS NEW
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Noteworthy changes in version 0.3.13 (2002-11-20) Noteworthy changes in version 0.3.13 (2002-11-20)

View File

@ -1,3 +1,62 @@
2002-12-04 Marcus Brinkmann <marcus@g10code.de>
* gpgme.h: Add prototype for gpgme_get_key.
* key.c (gpgme_get_key): New function.
* verify.c (gpgme_get_sig_key): Rewrite using gpgme_get_key.
* gpgme.h: Add prototypes for new interfaces
gpgme_key_sig_get_string_attr and gpgme_key_get_ulong_attr.
(enum GpgmeAttr): New attribute GPGME_ATTR_SIG_CLASS.
* gpgme.c (gpgme_set_keylist_mode): Allow GPGME_KEYLIST_MODE_SIGS.
* key.h (struct certsig_s): New members ALGO, NAME_PART,
EMAIL_PART, COMMENT_PART, NAME, SIG_STAT and SIG_CLASS.
* conversion.c (_gpgme_decode_c_string): Add new parameter LEN.
Use that to determine if allocation is desired or not.
* util.h: Adjust prototype of _gpgme_decode_c_string.
* keylist.c (keylist_colon_handler): Adjust caller of
_gpgme_decode_c_string.
* key.h (struct gpgme_key_s): New member last_uid.
* key.c (_gpgme_key_append_name): Rewritten using
_gpgme_decode_c_string and the last_uid pointer.
(my_isdigit): Macro removed.
(ALLOC_CHUNK): Likewise.
* keylist.c (set_userid_flags): Use last_uid member of KEY.
* context.h (struct user_id_s): New member last_certsig.
* key.h: Add prototype for _gpgme_key_add_certsig.
* key.c (_gpgme_key_add_certsig): New function.
(set_user_id_part): Move function before _gpgme_key_add_certsig.
(parse_user_id): Change first argument to SRC, add new arguments
NAME, EMAIL and COMMENT. Change code to use these arguments
instead going through UID. Move function before
_gpgme_add_certsig.
(parse_x509_user_id): Likewise.
(_gpgme_key_append_name): Adjust arguments to parse_x509_user_id
and parse_user_id invocation.
(one_certsig_as_xml): New function.
(one_uid_as_xml): Print signatures.
* context.h (struct gpgme_context_s): New member TMP_UID.
* keylist.c (keylist_colon_handler): Rewritten, implement "sig"
record entries.
* key.c (get_certsig): New function.
(gpgme_key_sig_get_string_attr): Likewise.
(gpgme_key_sig_get_ulong_attr): Likewise.
* keylist.c: Include <ctype.h>.
(my_isdigit): Macro removed.
(set_mainkey_trust_info): Use isdigit, not my_isdigit.
(set_userid_flags): Likewise.
(set_subkey_trust_info): Likewise.
(set_ownertrust): Likewise.
(finish_key): Move function up a bit and remove prototype.
* rungpg.c (gpg_keylist_ext): Correct precedence of signature
listing mode.
(gpg_keylist_ext): Implement signature listing mode.
2002-11-25 Marcus Brinkmann <marcus@g10code.de> 2002-11-25 Marcus Brinkmann <marcus@g10code.de>
* rungpg.c (_gpgme_gpg_spawn): Do not set parent fds to -1. * rungpg.c (_gpgme_gpg_spawn): Do not set parent fds to -1.

View File

@ -1,23 +1,22 @@
/* context.h /* context.h
* Copyright (C) 2000 Werner Koch (dd9jn) Copyright (C) 2000 Werner Koch (dd9jn)
* Copyright (C) 2001, 2002 g10 Code GmbH Copyright (C) 2001, 2002 g10 Code GmbH
*
* This file is part of GPGME. This file is part of GPGME.
*
* GPGME is free software; you can redistribute it and/or modify GPGME is free software; you can redistribute it and/or modify it
* it under the terms of the GNU General Public License as published by under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version. (at your option) any later version.
*
* GPGME is distributed in the hope that it will be useful, GPGME is distributed in the hope that it will be useful, but
* but WITHOUT ANY WARRANTY; without even the implied warranty of WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* GNU General Public License for more details. General Public License for more details.
*
* You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software along with GPGME; if not, write to the Free Software Foundation,
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
*/
#ifndef CONTEXT_H #ifndef CONTEXT_H
#define CONTEXT_H #define CONTEXT_H
@ -93,6 +92,7 @@ struct gpgme_context_s
/* Used by keylist.c. */ /* Used by keylist.c. */
GpgmeKey tmp_key; GpgmeKey tmp_key;
struct user_id_s *tmp_uid;
/* Something new is available. */ /* Something new is available. */
volatile int key_cond; volatile int key_cond;
struct key_queue_item_s *key_queue; struct key_queue_item_s *key_queue;
@ -124,6 +124,7 @@ struct user_id_s
unsigned int invalid : 1; unsigned int invalid : 1;
GpgmeValidity validity; GpgmeValidity validity;
struct certsig_s *certsigs; struct certsig_s *certsigs;
struct certsig_s *last_certsig;
const char *name_part; /* All 3 point into strings behind name */ const char *name_part; /* All 3 point into strings behind name */
const char *email_part; /* or to read-only strings. */ const char *email_part; /* or to read-only strings. */
const char *comment_part; const char *comment_part;

View File

@ -57,18 +57,29 @@ _gpgme_hextobyte (const byte *str)
} }
/* Decode the C formatted string SRC and store the result in the
buffer *DESTP which is LEN bytes long. If LEN is zero, then a
large enough buffer is allocated with malloc and *DESTP is set to
the result. Currently, LEN is only used to specify if allocation
is desired or not, the caller is expected to make sure that *DESTP
is large enough if LEN is not zero. */
GpgmeError GpgmeError
_gpgme_decode_c_string (const char *src, char **destp) _gpgme_decode_c_string (const char *src, char **destp, int len)
{ {
char *dest; char *dest;
/* We can malloc a buffer of the same length, because the converted if (len)
string will never be larger. */ dest = *destp;
dest = malloc (strlen (src) + 1); else
if (!dest) {
return mk_error (Out_Of_Core); /* We can malloc a buffer of the same length, because the converted
string will never be larger. */
dest = malloc (strlen (src) + 1);
if (!dest)
return mk_error (Out_Of_Core);
*destp = dest; *destp = dest;
}
while (*src) while (*src)
{ {

View File

@ -1,25 +1,26 @@
/* gpgme.c - GnuPG Made Easy /* gpgme.c - GnuPG Made Easy
* Copyright (C) 2000 Werner Koch (dd9jn) Copyright (C) 2000 Werner Koch (dd9jn)
* Copyright (C) 2001, 2002 g10 Code GmbH Copyright (C) 2001, 2002 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 General Public License as published by
* the Free Software Foundation; either version 2 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 General Public License for more details.
*
* You should have received a copy of the GNU 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
*/
This file is part of GPGME.
GPGME is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 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
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GPGME; 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> #include <config.h>
#endif
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -348,8 +349,9 @@ gpgme_set_keylist_mode (GpgmeCtx ctx, int mode)
return mk_error (Invalid_Value); return mk_error (Invalid_Value);
if (!((mode & GPGME_KEYLIST_MODE_LOCAL) if (!((mode & GPGME_KEYLIST_MODE_LOCAL)
|| (mode & GPGME_KEYLIST_MODE_EXTERN))) || (mode & GPGME_KEYLIST_MODE_EXTERN)
return mk_error (Invalid_Value); || (mode & GPGME_KEYLIST_MODE_SIGS)))
return mk_error (Invalid_Value);
ctx->keylist_mode = mode; ctx->keylist_mode = mode;
return 0; return 0;

View File

@ -196,7 +196,8 @@ typedef enum
GPGME_ATTR_CHAINID = 28, GPGME_ATTR_CHAINID = 28,
GPGME_ATTR_SIG_STATUS = 29, GPGME_ATTR_SIG_STATUS = 29,
GPGME_ATTR_ERRTOK = 30, GPGME_ATTR_ERRTOK = 30,
GPGME_ATTR_SIG_SUMMARY = 31 GPGME_ATTR_SIG_SUMMARY = 31,
GPGME_ATTR_SIG_CLASS = 32
} }
GpgmeAttr; GpgmeAttr;
@ -611,6 +612,13 @@ GpgmeError gpgme_data_rewind (GpgmeData dh);
/* Key and trust functions. */ /* Key and trust functions. */
/* Get the key with the fingerprint FPR from the key cache or from the
crypto backend. If FORCE_UPDATE is true, force a refresh of the
key from the crypto backend and replace the key in the cache, if
any. If SECRET is true, get the secret key. */
GpgmeError gpgme_get_key (GpgmeCtx ctx, const char *fpr, GpgmeKey *r_key,
int secret, int force_update);
/* Acquire a reference to KEY. */ /* Acquire a reference to KEY. */
void gpgme_key_ref (GpgmeKey key); void gpgme_key_ref (GpgmeKey key);
@ -635,6 +643,21 @@ const char *gpgme_key_get_string_attr (GpgmeKey key, GpgmeAttr what,
unsigned long gpgme_key_get_ulong_attr (GpgmeKey key, GpgmeAttr what, unsigned long gpgme_key_get_ulong_attr (GpgmeKey key, GpgmeAttr what,
const void *reserved, int idx); const void *reserved, int idx);
/* Return the value of the attribute WHAT of a signature on user ID
UID_IDX in KEY, which has to be representable by a string. IDX
specifies the signature. */
const char *gpgme_key_sig_get_string_attr (GpgmeKey key, int uid_idx,
GpgmeAttr what,
const void *reserved, int idx);
/* Return the value of the attribute WHAT of a signature on user ID
UID_IDX in KEY, which has to be representable by an unsigned
integer string. IDX specifies the signature. */
unsigned long gpgme_key_sig_get_ulong_attr (GpgmeKey key, int uid_idx,
GpgmeAttr what,
const void *reserved, int idx);
/* Release the trust item ITEM. */ /* Release the trust item ITEM. */
void gpgme_trust_item_release (GpgmeTrustItem item); void gpgme_trust_item_release (GpgmeTrustItem item);

View File

@ -1,25 +1,26 @@
/* key.c - Key and keyList objects /* key.c - Key objects.
* Copyright (C) 2000 Werner Koch (dd9jn) Copyright (C) 2000 Werner Koch (dd9jn)
* Copyright (C) 2001, 2002 g10 Code GmbH Copyright (C) 2001, 2002 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 General Public License as published by
* the Free Software Foundation; either version 2 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 General Public License for more details.
*
* You should have received a copy of the GNU 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
*/
This file is part of GPGME.
GPGME is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 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
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GPGME; 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> #include <config.h>
#endif
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -31,13 +32,11 @@
#include "key.h" #include "key.h"
#include "sema.h" #include "sema.h"
#define ALLOC_CHUNK 1024
#define my_isdigit(a) ((a) >='0' && (a) <= '9')
#if SIZEOF_UNSIGNED_INT < 4 #if SIZEOF_UNSIGNED_INT < 4
#error unsigned int too short to be used as a hash value #error unsigned int too short to be used as a hash value
#endif #endif
struct key_cache_item_s struct key_cache_item_s
{ {
struct key_cache_item_s *next; struct key_cache_item_s *next;
@ -82,6 +81,7 @@ hash_key (const char *fpr, unsigned int *rhash)
return 0; return 0;
} }
void void
_gpgme_key_cache_init (void) _gpgme_key_cache_init (void)
{ {
@ -251,7 +251,7 @@ _gpgme_key_cache_get (const char *fpr)
return NULL; return NULL;
} }
static const char * static const char *
pkalgo_to_string (int algo) pkalgo_to_string (int algo)
{ {
@ -288,12 +288,14 @@ key_new (GpgmeKey *r_key, int secret)
return 0; return 0;
} }
GpgmeError GpgmeError
_gpgme_key_new (GpgmeKey *r_key) _gpgme_key_new (GpgmeKey *r_key)
{ {
return key_new (r_key, 0); return key_new (r_key, 0);
} }
GpgmeError GpgmeError
_gpgme_key_new_secret (GpgmeKey *r_key) _gpgme_key_new_secret (GpgmeKey *r_key)
{ {
@ -317,7 +319,7 @@ gpgme_key_ref (GpgmeKey key)
UNLOCK (key_ref_lock); UNLOCK (key_ref_lock);
} }
static struct subkey_s * static struct subkey_s *
add_subkey (GpgmeKey key, int secret) add_subkey (GpgmeKey key, int secret)
{ {
@ -327,7 +329,7 @@ add_subkey (GpgmeKey key, int secret)
if (!k) if (!k)
return NULL; return NULL;
if(!(kk = key->keys.next)) if (!(kk = key->keys.next))
key->keys.next = k; key->keys.next = k;
else else
{ {
@ -354,7 +356,173 @@ _gpgme_key_add_secret_subkey (GpgmeKey key)
return add_subkey (key, 1); return add_subkey (key, 1);
} }
static char *
set_user_id_part (char *tail, const char *buf, size_t len)
{
while (len && (buf[len - 1] == ' ' || buf[len - 1] == '\t'))
len--;
for (; len; len--)
*tail++ = *buf++;
*tail++ = 0;
return tail;
}
static void
parse_user_id (const char *src, const char **name, const char **email,
const char **comment, char *tail)
{
const char *start = NULL;
int in_name = 0;
int in_email = 0;
int in_comment = 0;
while (*src)
{
if (in_email)
{
if (*src == '<')
/* Not legal but anyway. */
in_email++;
else if (*src == '>')
{
if (!--in_email && !*email)
{
*email = tail;
tail = set_user_id_part (tail, start, src - start);
}
}
}
else if (in_comment)
{
if (*src == '(')
in_comment++;
else if (*src == ')')
{
if (!--in_comment && !*comment)
{
*comment = tail;
tail = set_user_id_part (tail, start, src - start);
}
}
}
else if (*src == '<')
{
if (in_name)
{
if (!*name)
{
*name = tail;
tail = set_user_id_part (tail, start, src - start);
}
in_name = 0;
}
in_email = 1;
start = src + 1;
}
else if (*src == '(')
{
if (in_name)
{
if (!*name)
{
*name = tail;
tail = set_user_id_part (tail, start, src - start);
}
in_name = 0;
}
in_comment = 1;
start = src + 1;
}
else if (!in_name && *src != ' ' && *src != '\t')
{
in_name = 1;
start = src;
}
src++;
}
if (in_name)
{
if (!*name)
{
*name = tail;
tail = set_user_id_part (tail, start, src - start);
}
}
/* Let unused parts point to an EOS. */
tail--;
if (!*name)
*name = tail;
if (!*email)
*email = tail;
if (!*comment)
*comment = tail;
}
static void
parse_x509_user_id (const char *src, const char **name, const char **email,
const char **comment, char *tail)
{
if (*src == '<' && src[strlen (src) - 1] == '>')
*email = src;
/* Let unused parts point to an EOS. */
tail--;
if (!*name)
*name = tail;
if (!*email)
*email = tail;
if (!*comment)
*comment = tail;
}
struct certsig_s *
_gpgme_key_add_certsig (GpgmeKey key, char *src)
{
int src_len = src ? strlen (src) : 0;
struct user_id_s *uid;
struct certsig_s *certsig;
assert (key); /* XXX */
uid = key->last_uid;
assert (uid); /* XXX */
/* We can malloc a buffer of the same length, because the converted
string will never be larger. Actually we allocate it twice the
size, so that we are able to store the parsed stuff there too. */
certsig = calloc (1, sizeof (*certsig) + 2 * src_len + 3);
if (!certsig)
return NULL;
if (src)
{
char *dst = certsig->name;
_gpgme_decode_c_string (src, &dst, src_len + 1);
dst += src_len + 1;
if (key->x509)
parse_x509_user_id (src, &certsig->name_part, &certsig->email_part,
&certsig->comment_part, dst);
else
parse_user_id (src, &certsig->name_part, &certsig->email_part,
&certsig->comment_part, dst);
}
if (!uid->certsigs)
uid->certsigs = certsig;
if (uid->last_certsig)
uid->last_certsig->next = certsig;
uid->last_certsig = certsig;
return certsig;
}
/** /**
* gpgme_key_release: * gpgme_key_release:
* @key: Key Object or NULL * @key: Key Object or NULL
@ -406,6 +574,7 @@ gpgme_key_release (GpgmeKey key)
free (key); free (key);
} }
/** /**
* gpgme_key_unref: * gpgme_key_unref:
* @key: Key Object * @key: Key Object
@ -418,237 +587,41 @@ gpgme_key_unref (GpgmeKey key)
gpgme_key_release (key); gpgme_key_release (key);
} }
static char * /* Take a name from the --with-colon listing, remove certain escape
set_user_id_part (char *tail, const char *buf, size_t len) sequences sequences and put it into the list of UIDs. */
{
while (len && (buf[len-1] == ' ' || buf[len-1] == '\t'))
len--;
for (; len; len--)
*tail++ = *buf++;
*tail++ = 0;
return tail;
}
static void
parse_user_id (struct user_id_s *uid, char *tail)
{
const char *s, *start=NULL;
int in_name = 0;
int in_email = 0;
int in_comment = 0;
for (s = uid->name; *s; s++)
{
if (in_email)
{
if (*s == '<')
/* Not legal but anyway. */
in_email++;
else if (*s == '>')
{
if (!--in_email)
{
if (!uid->email_part)
{
uid->email_part = tail;
tail = set_user_id_part ( tail, start, s-start );
}
}
}
}
else if (in_comment)
{
if (*s == '(')
in_comment++;
else if (*s== ')')
{
if (!--in_comment)
{
if (!uid->comment_part)
{
uid->comment_part = tail;
tail = set_user_id_part ( tail, start, s-start );
}
}
}
}
else if (*s == '<')
{
if (in_name)
{
if (!uid->name_part)
{
uid->name_part = tail;
tail = set_user_id_part (tail, start, s-start);
}
in_name = 0;
}
in_email = 1;
start = s+1;
}
else if (*s == '(')
{
if (in_name)
{
if (!uid->name_part)
{
uid->name_part = tail;
tail = set_user_id_part (tail, start, s-start );
}
in_name = 0;
}
in_comment = 1;
start = s+1;
}
else if (!in_name && *s != ' ' && *s != '\t')
{
in_name = 1;
start = s;
}
}
if (in_name)
{
if (!uid->name_part)
{
uid->name_part = tail;
tail = set_user_id_part (tail, start, s-start);
}
}
/* Let unused parts point to an EOS. */
tail--;
if (!uid->name_part)
uid->name_part = tail;
if (!uid->email_part)
uid->email_part = tail;
if (!uid->comment_part)
uid->comment_part = tail;
}
static void
parse_x509_user_id (struct user_id_s *uid, char *tail)
{
const char *s;
s=uid->name;
if (*s == '<' && s[strlen (s) - 1] == '>')
uid->email_part = s;
/* Let unused parts point to an EOS. */
tail--;
if (!uid->name_part)
uid->name_part = tail;
if (!uid->email_part)
uid->email_part = tail;
if (!uid->comment_part)
uid->comment_part = tail;
}
/*
* Take a name from the --with-colon listing, remove certain escape sequences
* sequences and put it into the list of UIDs
*/
GpgmeError GpgmeError
_gpgme_key_append_name (GpgmeKey key, const char *s) _gpgme_key_append_name (GpgmeKey key, const char *src)
{ {
struct user_id_s *uid; struct user_id_s *uid;
char *d; char *dst;
int src_len = strlen (src);
assert (key); assert (key);
/* We can malloc a buffer of the same length, because the converted /* We can malloc a buffer of the same length, because the converted
string will never be larger. Actually we allocate it twice the string will never be larger. Actually we allocate it twice the
size, so that we are able to store the parsed stuff there too. */ size, so that we are able to store the parsed stuff there too. */
uid = malloc (sizeof *uid + 2*strlen (s)+3); uid = malloc (sizeof (*uid) + 2 * src_len + 3);
if (!uid) if (!uid)
return mk_error (Out_Of_Core); return mk_error (Out_Of_Core);
memset (uid, 0, sizeof *uid); memset (uid, 0, sizeof *uid);
d = uid->name;
while (*s) dst = uid->name;
{ _gpgme_decode_c_string (src, &dst, src_len + 1);
if (*s != '\\')
*d++ = *s++; dst += src_len + 1;
else if (s[1] == '\\')
{
s++;
*d++ = *s++;
}
else if (s[1] == 'n')
{
s += 2;
*d++ = '\n';
}
else if (s[1] == 'r')
{
s += 2;
*d++ = '\r';
}
else if (s[1] == 'v')
{
s += 2;
*d++ = '\v';
}
else if (s[1] == 'b')
{
s += 2;
*d++ = '\b';
}
else if (s[1] == '0')
{
/* Hmmm: no way to express this */
s += 2;
*d++ = '\\';
*d++ = '\0';
}
else if (s[1] == 'x' && isxdigit (s[2]) && isxdigit (s[3]))
{
int val = _gpgme_hextobyte (&s[2]);
if (val == -1)
{
/* Should not happen. */
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
}
else
{
if (!val)
{
*d++ = '\\';
*d++ = '\0';
}
else
*(byte*)d++ = val;
s += 4;
}
}
else
{
/* should not happen */
s++;
*d++ = '\\';
*d++ = *s++;
}
}
*d++ = 0;
if (key->x509) if (key->x509)
parse_x509_user_id (uid, d); parse_x509_user_id (src, &uid->name_part, &uid->email_part,
&uid->comment_part, dst);
else else
parse_user_id (uid, d); parse_user_id (src, &uid->name_part, &uid->email_part,
&uid->comment_part, dst);
if (key->uids) if (!key->uids)
{
struct user_id_s *u = key->uids;
while (u->next)
u = u->next;
u->next = uid;
}
else
key->uids = uid; key->uids = uid;
if (key->last_uid)
key->last_uid->next = uid;
key->last_uid = uid;
return 0; return 0;
} }
@ -662,6 +635,7 @@ add_otag (GpgmeData d, const char *tag)
_gpgme_data_append_string (d, ">"); _gpgme_data_append_string (d, ">");
} }
static void static void
add_ctag (GpgmeData d, const char *tag) add_ctag (GpgmeData d, const char *tag)
{ {
@ -670,6 +644,7 @@ add_ctag (GpgmeData d, const char *tag)
_gpgme_data_append_string (d, ">\n"); _gpgme_data_append_string (d, ">\n");
} }
static void static void
add_tag_and_string (GpgmeData d, const char *tag, const char *string) add_tag_and_string (GpgmeData d, const char *tag, const char *string)
{ {
@ -678,6 +653,7 @@ add_tag_and_string (GpgmeData d, const char *tag, const char *string)
add_ctag (d, tag); add_ctag (d, tag);
} }
static void static void
add_tag_and_uint (GpgmeData d, const char *tag, unsigned int val) add_tag_and_uint (GpgmeData d, const char *tag, unsigned int val)
{ {
@ -686,6 +662,7 @@ add_tag_and_uint (GpgmeData d, const char *tag, unsigned int val)
add_tag_and_string (d, tag, buf); add_tag_and_string (d, tag, buf);
} }
static void static void
add_tag_and_time (GpgmeData d, const char *tag, time_t val) add_tag_and_time (GpgmeData d, const char *tag, time_t val)
{ {
@ -697,22 +674,55 @@ add_tag_and_time (GpgmeData d, const char *tag, time_t val)
add_tag_and_string (d, tag, buf); add_tag_and_string (d, tag, buf);
} }
static void static void
one_uid_as_xml (GpgmeData d, struct user_id_s *u) one_certsig_as_xml (GpgmeData data, struct certsig_s *certsig)
{ {
_gpgme_data_append_string (d, " <userid>\n"); _gpgme_data_append_string (data, " <signature>\n");
if (u->invalid) if (certsig->flags.invalid)
_gpgme_data_append_string (d, " <invalid/>\n"); _gpgme_data_append_string (data, " <invalid/>\n");
if (u->revoked) if (certsig->flags.revoked)
_gpgme_data_append_string (d, " <revoked/>\n"); _gpgme_data_append_string (data, " <revoked/>\n");
add_tag_and_string (d, "raw", u->name); if (certsig->flags.expired)
if (*u->name_part) _gpgme_data_append_string (data, " <expired/>\n");
add_tag_and_string (d, "name", u->name_part); add_tag_and_string (data, "keyid", certsig->keyid);
if (*u->email_part) add_tag_and_uint (data, "algo", certsig->algo);
add_tag_and_string (d, "email", u->email_part); add_tag_and_time (data, "created", certsig->timestamp);
if (*u->comment_part) add_tag_and_time (data, "expire", certsig->expires_at);
add_tag_and_string (d, "comment", u->comment_part); if (*certsig->name)
_gpgme_data_append_string (d, " </userid>\n"); add_tag_and_string (data, "raw", certsig->name);
if (*certsig->name_part)
add_tag_and_string (data, "name", certsig->name_part);
if (*certsig->email_part)
add_tag_and_string (data, "email", certsig->email_part);
if (*certsig->comment_part)
add_tag_and_string (data, "comment", certsig->comment_part);
_gpgme_data_append_string (data, " </signature>\n");
}
static void
one_uid_as_xml (GpgmeData data, struct user_id_s *uid)
{
struct certsig_s *certsig;
_gpgme_data_append_string (data, " <userid>\n");
if (uid->invalid)
_gpgme_data_append_string (data, " <invalid/>\n");
if (uid->revoked)
_gpgme_data_append_string (data, " <revoked/>\n");
add_tag_and_string (data, "raw", uid->name);
if (*uid->name_part)
add_tag_and_string (data, "name", uid->name_part);
if (*uid->email_part)
add_tag_and_string (data, "email", uid->email_part);
if (*uid->comment_part)
add_tag_and_string (data, "comment", uid->comment_part);
/* Now the signatures. */
for (certsig = uid->certsigs; certsig; certsig = certsig->next)
one_certsig_as_xml (data, certsig);
_gpgme_data_append_string (data, " </userid>\n");
} }
@ -817,8 +827,8 @@ capabilities_to_string (struct subkey_s *k)
"esc" "esc"
}; };
return strings[(!!k->flags.can_encrypt << 2) return strings[(!!k->flags.can_encrypt << 2)
| (!!k->flags.can_sign << 1) | (!!k->flags.can_sign << 1)
| (!!k->flags.can_certify )]; | (!!k->flags.can_certify)];
} }
@ -972,6 +982,7 @@ gpgme_key_get_string_attr (GpgmeKey key, GpgmeAttr what,
case GPGME_ATTR_SIG_STATUS: case GPGME_ATTR_SIG_STATUS:
case GPGME_ATTR_SIG_SUMMARY: case GPGME_ATTR_SIG_SUMMARY:
case GPGME_ATTR_ERRTOK: case GPGME_ATTR_ERRTOK:
case GPGME_ATTR_SIG_CLASS:
/* Not of any use here. */ /* Not of any use here. */
break; break;
} }
@ -1102,3 +1113,154 @@ gpgme_key_get_ulong_attr (GpgmeKey key, GpgmeAttr what,
return val; return val;
} }
static struct certsig_s *
get_certsig (GpgmeKey key, int uid_idx, int idx)
{
struct user_id_s *uid;
struct certsig_s *certsig;
if (!key || uid_idx < 0 || idx < 0)
return NULL;
uid = key->uids;
while (uid && uid_idx > 0)
{
uid = uid->next;
uid_idx--;
}
if (!uid)
return NULL;
certsig = uid->certsigs;
while (certsig && idx > 0)
{
certsig = certsig->next;
idx--;
}
return certsig;
}
const char *
gpgme_key_sig_get_string_attr (GpgmeKey key, int uid_idx, GpgmeAttr what,
const void *reserved, int idx)
{
struct certsig_s *certsig = get_certsig (key, uid_idx, idx);
if (!certsig || reserved)
return NULL;
switch (what)
{
case GPGME_ATTR_KEYID:
return certsig->keyid;
case GPGME_ATTR_ALGO:
return pkalgo_to_string (certsig->algo);
case GPGME_ATTR_USERID:
return certsig->name;
case GPGME_ATTR_NAME:
return certsig->name_part;
case GPGME_ATTR_EMAIL:
return certsig->email_part;
case GPGME_ATTR_COMMENT:
return certsig->comment_part;
default:
return NULL;
}
}
unsigned long
gpgme_key_sig_get_ulong_attr (GpgmeKey key, int uid_idx, GpgmeAttr what,
const void *reserved, int idx)
{
struct certsig_s *certsig = get_certsig (key, uid_idx, idx);
if (!certsig || reserved)
return 0;
switch (what)
{
case GPGME_ATTR_ALGO:
return (unsigned long) certsig->algo;
case GPGME_ATTR_CREATED:
return certsig->timestamp < 0 ? 0L : (unsigned long) certsig->timestamp;
case GPGME_ATTR_EXPIRE:
return certsig->expires_at < 0 ? 0L : (unsigned long) certsig->expires_at;
case GPGME_ATTR_KEY_REVOKED:
return certsig->flags.revoked;
case GPGME_ATTR_KEY_INVALID:
return certsig->flags.invalid;
case GPGME_ATTR_KEY_EXPIRED:
return certsig->flags.expired;
case GPGME_ATTR_SIG_CLASS:
return certsig->sig_class;
case GPGME_ATTR_SIG_STATUS:
return certsig->sig_stat;
default:
return 0;
}
}
/* Get the key with the fingerprint FPR from the key cache or from the
crypto backend. If FORCE_UPDATE is true, force a refresh of the
key from the crypto backend and replace the key in the cache, if
any. If SECRET is true, get the secret key. */
GpgmeError
gpgme_get_key (GpgmeCtx ctx, const char *fpr, GpgmeKey *r_key,
int secret, int force_update)
{
GpgmeCtx listctx;
GpgmeError err;
if (!ctx || !r_key)
return mk_error (Invalid_Value);
if (ctx->pending)
return mk_error (Busy);
if (strlen (fpr) < 16) /* We have at least a key ID. */
return mk_error (Invalid_Key);
if (!force_update)
{
*r_key = _gpgme_key_cache_get (fpr);
if (*r_key)
{
/* If the primary UID (if available) has no signatures, and
we are in the signature listing keylist mode, then try to
update the key below before returning. */
if (!((ctx->keylist_mode & GPGME_KEYLIST_MODE_SIGS)
&& (*r_key)->uids && !(*r_key)->uids->certsigs))
return 0;
}
}
/* Fixme: This can be optimized by keeping an internal context
used for such key listings. */
err = gpgme_new (&listctx);
if (err)
return err;
gpgme_set_protocol (listctx, gpgme_get_protocol (ctx));
gpgme_set_keylist_mode (listctx, ctx->keylist_mode);
err = gpgme_op_keylist_start (listctx, fpr, secret);
if (!err)
err = gpgme_op_keylist_next (listctx, r_key);
gpgme_release (listctx);
return err;
}

View File

@ -1,23 +1,22 @@
/* key.h /* key.h - Key handling interface.
* Copyright (C) 2000 Werner Koch (dd9jn) Copyright (C) 2000 Werner Koch (dd9jn)
* Copyright (C) 2001 g10 Code GmbH Copyright (C) 2001, 2002 g10 Code GmbH
*
* This file is part of GPGME. This file is part of GPGME.
*
* GPGME is free software; you can redistribute it and/or modify GPGME is free software; you can redistribute it and/or modify it
* it under the terms of the GNU General Public License as published by under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version. (at your option) any later version.
*
* GPGME is distributed in the hope that it will be useful, GPGME is distributed in the hope that it will be useful, but
* but WITHOUT ANY WARRANTY; without even the implied warranty of WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* GNU General Public License for more details. General Public License for more details.
*
* You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software along with GPGME; if not, write to the Free Software Foundation,
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
*/
#ifndef KEY_H #ifndef KEY_H
#define KEY_H #define KEY_H
@ -26,68 +25,86 @@
#include "types.h" #include "types.h"
#include "context.h" #include "context.h"
struct certsig_s {
struct certsig_s
{
struct certsig_s *next; struct certsig_s *next;
struct { struct
unsigned int revoked:1 ; {
unsigned int expired:1 ; unsigned int revoked : 1;
unsigned int invalid:1 ; unsigned int expired : 1;
unsigned int invalid : 1;
unsigned int exportable : 1;
} flags; } flags;
char keyid[16+1]; unsigned int algo;
time_t timestamp; /* -1 for invalid, 0 for not available */ char keyid[16 + 1];
time_t expires_at; /* 0 for does not expires */ time_t timestamp; /* -1 for invalid, 0 for not available. */
time_t expires_at; /* 0 for no expiration. */
GpgmeSigStat sig_stat;
unsigned int sig_class;
const char *name_part; /* All 3 point into strings behind name */
const char *email_part; /* or to read-only strings. */
const char *comment_part;
char name[1];
}; };
struct subkey_s {
struct subkey_s
{
struct subkey_s *next; struct subkey_s *next;
unsigned int secret:1; unsigned int secret:1;
struct { struct
unsigned int revoked:1 ; {
unsigned int expired:1 ; unsigned int revoked : 1;
unsigned int disabled:1 ; unsigned int expired : 1;
unsigned int invalid:1 ; unsigned int disabled : 1;
unsigned int can_encrypt:1; unsigned int invalid : 1;
unsigned int can_sign:1; unsigned int can_encrypt : 1;
unsigned int can_certify:1; unsigned int can_sign : 1;
unsigned int can_certify : 1;
} flags; } flags;
unsigned int key_algo; unsigned int key_algo;
unsigned int key_len; unsigned int key_len;
char keyid[16+1]; char keyid[16 + 1];
char *fingerprint; /* malloced hex digits */ char *fingerprint; /* Malloced hex digits. */
time_t timestamp; /* -1 for invalid, 0 for not available */ time_t timestamp; /* -1 for invalid, 0 for not available. */
time_t expires_at; /* 0 for does not expires */ time_t expires_at; /* 0 for does not expires. */
}; };
struct gpgme_key_s {
struct { struct gpgme_key_s
unsigned int revoked:1 ; {
unsigned int expired:1 ; struct
unsigned int disabled:1 ; {
unsigned int invalid:1 ; unsigned int revoked : 1;
unsigned int can_encrypt:1; unsigned int expired : 1;
unsigned int can_sign:1; unsigned int disabled : 1;
unsigned int can_certify:1; unsigned int invalid : 1;
unsigned int can_encrypt : 1;
unsigned int can_sign : 1;
unsigned int can_certify : 1;
} gloflags; } gloflags;
unsigned int ref_count; unsigned int ref_count;
unsigned int secret:1; unsigned int secret : 1;
unsigned int x509:1; unsigned int x509 : 1;
char *issuer_serial; /* malloced string used only with X.509 */ char *issuer_serial; /* Malloced string used only with X.509. */
char *issuer_name; /* ditto */ char *issuer_name; /* Ditto. */
char *chain_id; /* ditto */ char *chain_id; /* Ditto. */
GpgmeValidity otrust; /* only used with OpenPGP */ GpgmeValidity otrust; /* Only used with OpenPGP. */
struct subkey_s keys; struct subkey_s keys;
struct user_id_s *uids; struct user_id_s *uids;
struct user_id_s *last_uid;
}; };
void _gpgme_key_cache_init (void); void _gpgme_key_cache_init (void);
void _gpgme_key_cache_add (GpgmeKey key); void _gpgme_key_cache_add (GpgmeKey key);
GpgmeKey _gpgme_key_cache_get (const char *fpr); GpgmeKey _gpgme_key_cache_get (const char *fpr);
struct certsig_s *_gpgme_key_add_certsig (GpgmeKey key, char *src);
struct subkey_s *_gpgme_key_add_subkey (GpgmeKey key); struct subkey_s *_gpgme_key_add_subkey (GpgmeKey key);
struct subkey_s *_gpgme_key_add_secret_subkey (GpgmeKey key); struct subkey_s *_gpgme_key_add_secret_subkey (GpgmeKey key);
GpgmeError _gpgme_key_append_name ( GpgmeKey key, const char *s ); GpgmeError _gpgme_key_append_name (GpgmeKey key, const char *str);
#endif /* KEY_H */
#endif /* KEY_H */

File diff suppressed because it is too large Load Diff

View File

@ -1486,10 +1486,9 @@ gpg_keylist (void *engine, const char *pattern, int secret_only,
if (!err) if (!err)
err = add_arg (gpg, "--with-fingerprint"); err = add_arg (gpg, "--with-fingerprint");
if (!err) if (!err)
err = add_arg (gpg, (keylist_mode & GPGME_KEYLIST_MODE_SIGS) ? err = add_arg (gpg, secret_only ? "--list-secret-keys"
"--check-sigs" : : ((keylist_mode & GPGME_KEYLIST_MODE_SIGS)
secret_only ? "--list-secret-keys" ? "--check-sigs" : "--list-keys"));
: "--list-keys");
/* Tell the gpg object about the data. */ /* Tell the gpg object about the data. */
if (!err) if (!err)
@ -1519,7 +1518,9 @@ gpg_keylist_ext (void *engine, const char *pattern[], int secret_only,
if (!err) if (!err)
err = add_arg (gpg, "--with-fingerprint"); err = add_arg (gpg, "--with-fingerprint");
if (!err) if (!err)
err = add_arg (gpg, secret_only ? "--list-secret-keys" : "--list-keys"); err = add_arg (gpg, secret_only ? "--list-secret-keys"
: ((keylist_mode & GPGME_KEYLIST_MODE_SIGS)
? "--check-sigs" : "--list-keys"));
/* Tell the gpg object about the data. */ /* Tell the gpg object about the data. */
if (!err) if (!err)

View File

@ -85,7 +85,13 @@ FILE *fopencookie (void *cookie, const char *opentype,
/*-- conversion.c --*/ /*-- conversion.c --*/
GpgmeError _gpgme_decode_c_string (const char *src, char **destp); /* Decode the C formatted string SRC and store the result in the
buffer *DESTP which is LEN bytes long. If LEN is zero, then a
large enough buffer is allocated with malloc and *DESTP is set to
the result. Currently, LEN is only used to specify if allocation
is desired or not, the caller is expected to make sure that *DESTP
is large enough if LEN is not zero. */
GpgmeError _gpgme_decode_c_string (const char *src, char **destp, int len);
int _gpgme_hextobyte (const byte *str); int _gpgme_hextobyte (const byte *str);
#endif /* UTIL_H */ #endif /* UTIL_H */

View File

@ -643,42 +643,20 @@ gpgme_get_sig_ulong_attr (GpgmeCtx c, int idx, GpgmeAttr what, int reserved)
* indicate that there are no more signatures. * indicate that there are no more signatures.
**/ **/
GpgmeError GpgmeError
gpgme_get_sig_key (GpgmeCtx c, int idx, GpgmeKey *r_key) gpgme_get_sig_key (GpgmeCtx ctx, int idx, GpgmeKey *r_key)
{ {
VerifyResult result; VerifyResult result;
GpgmeError err = 0;
if (!c || !r_key) if (!ctx || !r_key)
return mk_error (Invalid_Value); return mk_error (Invalid_Value);
if (c->pending || !c->result.verify) if (ctx->pending || !ctx->result.verify)
return mk_error (Busy); return mk_error (Busy);
for (result = c->result.verify; for (result = ctx->result.verify;
result && idx > 0; result = result->next, idx--) result && idx > 0; result = result->next, idx--)
; ;
if (!result) if (!result)
return mk_error (EOF); return mk_error (EOF);
if (strlen(result->fpr) < 16) /* We have at least a key ID. */ return gpgme_get_key (ctx, result->fpr, r_key, 0, 0);
return mk_error (Invalid_Key);
*r_key = _gpgme_key_cache_get (result->fpr);
if (!*r_key)
{
GpgmeCtx listctx;
/* Fixme: This can be optimized by keeping an internal context
used for such key listings. */
err = gpgme_new (&listctx);
if (err)
return err;
gpgme_set_protocol (listctx, gpgme_get_protocol (c));
gpgme_set_keylist_mode (listctx, c->keylist_mode);
err = gpgme_op_keylist_start (listctx, result->fpr, 0);
if (!err)
err = gpgme_op_keylist_next (listctx, r_key);
gpgme_release (listctx);
}
return err;
} }