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:
parent
7394638cdb
commit
1b495c5140
11
NEWS
11
NEWS
@ -1,6 +1,12 @@
|
||||
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.
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@ -23,6 +29,11 @@ gpgme_op_verify CHANGED: Take different data objects for
|
||||
gpgme_op_verify_start CHANGED: See gpgme_op_verify.
|
||||
gpgme_check_engine REMOVED: Deprecated since 0.3.0.
|
||||
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)
|
||||
|
@ -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>
|
||||
|
||||
* rungpg.c (_gpgme_gpg_spawn): Do not set parent fds to -1.
|
||||
|
@ -1,23 +1,22 @@
|
||||
/* context.h
|
||||
* Copyright (C) 2000 Werner Koch (dd9jn)
|
||||
* 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
|
||||
*/
|
||||
Copyright (C) 2000 Werner Koch (dd9jn)
|
||||
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 GPGME; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#ifndef CONTEXT_H
|
||||
#define CONTEXT_H
|
||||
@ -93,6 +92,7 @@ struct gpgme_context_s
|
||||
|
||||
/* Used by keylist.c. */
|
||||
GpgmeKey tmp_key;
|
||||
struct user_id_s *tmp_uid;
|
||||
/* Something new is available. */
|
||||
volatile int key_cond;
|
||||
struct key_queue_item_s *key_queue;
|
||||
@ -124,6 +124,7 @@ struct user_id_s
|
||||
unsigned int invalid : 1;
|
||||
GpgmeValidity validity;
|
||||
struct certsig_s *certsigs;
|
||||
struct certsig_s *last_certsig;
|
||||
const char *name_part; /* All 3 point into strings behind name */
|
||||
const char *email_part; /* or to read-only strings. */
|
||||
const char *comment_part;
|
||||
|
@ -57,11 +57,21 @@ _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
|
||||
_gpgme_decode_c_string (const char *src, char **destp)
|
||||
_gpgme_decode_c_string (const char *src, char **destp, int len)
|
||||
{
|
||||
char *dest;
|
||||
|
||||
if (len)
|
||||
dest = *destp;
|
||||
else
|
||||
{
|
||||
/* We can malloc a buffer of the same length, because the converted
|
||||
string will never be larger. */
|
||||
dest = malloc (strlen (src) + 1);
|
||||
@ -69,6 +79,7 @@ _gpgme_decode_c_string (const char *src, char **destp)
|
||||
return mk_error (Out_Of_Core);
|
||||
|
||||
*destp = dest;
|
||||
}
|
||||
|
||||
while (*src)
|
||||
{
|
||||
|
@ -1,25 +1,26 @@
|
||||
/* gpgme.c - GnuPG Made Easy
|
||||
* Copyright (C) 2000 Werner Koch (dd9jn)
|
||||
* 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
|
||||
*/
|
||||
Copyright (C) 2000 Werner Koch (dd9jn)
|
||||
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 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>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@ -348,7 +349,8 @@ gpgme_set_keylist_mode (GpgmeCtx ctx, int mode)
|
||||
return mk_error (Invalid_Value);
|
||||
|
||||
if (!((mode & GPGME_KEYLIST_MODE_LOCAL)
|
||||
|| (mode & GPGME_KEYLIST_MODE_EXTERN)))
|
||||
|| (mode & GPGME_KEYLIST_MODE_EXTERN)
|
||||
|| (mode & GPGME_KEYLIST_MODE_SIGS)))
|
||||
return mk_error (Invalid_Value);
|
||||
|
||||
ctx->keylist_mode = mode;
|
||||
|
@ -196,7 +196,8 @@ typedef enum
|
||||
GPGME_ATTR_CHAINID = 28,
|
||||
GPGME_ATTR_SIG_STATUS = 29,
|
||||
GPGME_ATTR_ERRTOK = 30,
|
||||
GPGME_ATTR_SIG_SUMMARY = 31
|
||||
GPGME_ATTR_SIG_SUMMARY = 31,
|
||||
GPGME_ATTR_SIG_CLASS = 32
|
||||
}
|
||||
GpgmeAttr;
|
||||
|
||||
@ -611,6 +612,13 @@ GpgmeError gpgme_data_rewind (GpgmeData dh);
|
||||
|
||||
/* 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. */
|
||||
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,
|
||||
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. */
|
||||
void gpgme_trust_item_release (GpgmeTrustItem item);
|
||||
|
||||
|
674
gpgme/key.c
674
gpgme/key.c
@ -1,25 +1,26 @@
|
||||
/* key.c - Key and keyList objects
|
||||
* Copyright (C) 2000 Werner Koch (dd9jn)
|
||||
* 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
|
||||
*/
|
||||
/* key.c - Key objects.
|
||||
Copyright (C) 2000 Werner Koch (dd9jn)
|
||||
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 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>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@ -31,13 +32,11 @@
|
||||
#include "key.h"
|
||||
#include "sema.h"
|
||||
|
||||
#define ALLOC_CHUNK 1024
|
||||
#define my_isdigit(a) ((a) >='0' && (a) <= '9')
|
||||
|
||||
#if SIZEOF_UNSIGNED_INT < 4
|
||||
#error unsigned int too short to be used as a hash value
|
||||
#endif
|
||||
|
||||
|
||||
struct key_cache_item_s
|
||||
{
|
||||
struct key_cache_item_s *next;
|
||||
@ -82,6 +81,7 @@ hash_key (const char *fpr, unsigned int *rhash)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
_gpgme_key_cache_init (void)
|
||||
{
|
||||
@ -251,7 +251,7 @@ _gpgme_key_cache_get (const char *fpr)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static const char *
|
||||
pkalgo_to_string (int algo)
|
||||
{
|
||||
@ -288,12 +288,14 @@ key_new (GpgmeKey *r_key, int secret)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
GpgmeError
|
||||
_gpgme_key_new (GpgmeKey *r_key)
|
||||
{
|
||||
return key_new (r_key, 0);
|
||||
}
|
||||
|
||||
|
||||
GpgmeError
|
||||
_gpgme_key_new_secret (GpgmeKey *r_key)
|
||||
{
|
||||
@ -317,7 +319,7 @@ gpgme_key_ref (GpgmeKey key)
|
||||
UNLOCK (key_ref_lock);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static struct subkey_s *
|
||||
add_subkey (GpgmeKey key, int secret)
|
||||
{
|
||||
@ -327,7 +329,7 @@ add_subkey (GpgmeKey key, int secret)
|
||||
if (!k)
|
||||
return NULL;
|
||||
|
||||
if(!(kk = key->keys.next))
|
||||
if (!(kk = key->keys.next))
|
||||
key->keys.next = k;
|
||||
else
|
||||
{
|
||||
@ -354,7 +356,173 @@ _gpgme_key_add_secret_subkey (GpgmeKey key)
|
||||
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:
|
||||
* @key: Key Object or NULL
|
||||
@ -406,6 +574,7 @@ gpgme_key_release (GpgmeKey key)
|
||||
free (key);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* gpgme_key_unref:
|
||||
* @key: Key Object
|
||||
@ -418,237 +587,41 @@ gpgme_key_unref (GpgmeKey key)
|
||||
gpgme_key_release (key);
|
||||
}
|
||||
|
||||
|
||||
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 (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
|
||||
*/
|
||||
|
||||
/* Take a name from the --with-colon listing, remove certain escape
|
||||
sequences sequences and put it into the list of UIDs. */
|
||||
GpgmeError
|
||||
_gpgme_key_append_name (GpgmeKey key, const char *s)
|
||||
_gpgme_key_append_name (GpgmeKey key, const char *src)
|
||||
{
|
||||
struct user_id_s *uid;
|
||||
char *d;
|
||||
char *dst;
|
||||
int src_len = strlen (src);
|
||||
|
||||
assert (key);
|
||||
/* 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. */
|
||||
uid = malloc (sizeof *uid + 2*strlen (s)+3);
|
||||
uid = malloc (sizeof (*uid) + 2 * src_len + 3);
|
||||
if (!uid)
|
||||
return mk_error (Out_Of_Core);
|
||||
memset (uid, 0, sizeof *uid);
|
||||
d = uid->name;
|
||||
|
||||
while (*s)
|
||||
{
|
||||
if (*s != '\\')
|
||||
*d++ = *s++;
|
||||
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;
|
||||
dst = uid->name;
|
||||
_gpgme_decode_c_string (src, &dst, src_len + 1);
|
||||
|
||||
dst += src_len + 1;
|
||||
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
|
||||
parse_user_id (uid, d);
|
||||
parse_user_id (src, &uid->name_part, &uid->email_part,
|
||||
&uid->comment_part, dst);
|
||||
|
||||
if (key->uids)
|
||||
{
|
||||
struct user_id_s *u = key->uids;
|
||||
while (u->next)
|
||||
u = u->next;
|
||||
u->next = uid;
|
||||
}
|
||||
else
|
||||
if (!key->uids)
|
||||
key->uids = uid;
|
||||
if (key->last_uid)
|
||||
key->last_uid->next = uid;
|
||||
key->last_uid = uid;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -662,6 +635,7 @@ add_otag (GpgmeData d, const char *tag)
|
||||
_gpgme_data_append_string (d, ">");
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
add_ctag (GpgmeData d, const char *tag)
|
||||
{
|
||||
@ -670,6 +644,7 @@ add_ctag (GpgmeData d, const char *tag)
|
||||
_gpgme_data_append_string (d, ">\n");
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
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");
|
||||
if (u->invalid)
|
||||
_gpgme_data_append_string (d, " <invalid/>\n");
|
||||
if (u->revoked)
|
||||
_gpgme_data_append_string (d, " <revoked/>\n");
|
||||
add_tag_and_string (d, "raw", u->name);
|
||||
if (*u->name_part)
|
||||
add_tag_and_string (d, "name", u->name_part);
|
||||
if (*u->email_part)
|
||||
add_tag_and_string (d, "email", u->email_part);
|
||||
if (*u->comment_part)
|
||||
add_tag_and_string (d, "comment", u->comment_part);
|
||||
_gpgme_data_append_string (d, " </userid>\n");
|
||||
_gpgme_data_append_string (data, " <signature>\n");
|
||||
if (certsig->flags.invalid)
|
||||
_gpgme_data_append_string (data, " <invalid/>\n");
|
||||
if (certsig->flags.revoked)
|
||||
_gpgme_data_append_string (data, " <revoked/>\n");
|
||||
if (certsig->flags.expired)
|
||||
_gpgme_data_append_string (data, " <expired/>\n");
|
||||
add_tag_and_string (data, "keyid", certsig->keyid);
|
||||
add_tag_and_uint (data, "algo", certsig->algo);
|
||||
add_tag_and_time (data, "created", certsig->timestamp);
|
||||
add_tag_and_time (data, "expire", certsig->expires_at);
|
||||
if (*certsig->name)
|
||||
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");
|
||||
}
|
||||
|
||||
|
||||
@ -818,7 +828,7 @@ capabilities_to_string (struct subkey_s *k)
|
||||
};
|
||||
return strings[(!!k->flags.can_encrypt << 2)
|
||||
| (!!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_SUMMARY:
|
||||
case GPGME_ATTR_ERRTOK:
|
||||
case GPGME_ATTR_SIG_CLASS:
|
||||
/* Not of any use here. */
|
||||
break;
|
||||
}
|
||||
@ -1102,3 +1113,154 @@ gpgme_key_get_ulong_attr (GpgmeKey key, GpgmeAttr what,
|
||||
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;
|
||||
}
|
||||
|
135
gpgme/key.h
135
gpgme/key.h
@ -1,23 +1,22 @@
|
||||
/* key.h
|
||||
* Copyright (C) 2000 Werner Koch (dd9jn)
|
||||
* Copyright (C) 2001 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
|
||||
*/
|
||||
/* key.h - Key handling interface.
|
||||
Copyright (C) 2000 Werner Koch (dd9jn)
|
||||
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 GPGME; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#ifndef KEY_H
|
||||
#define KEY_H
|
||||
@ -26,68 +25,86 @@
|
||||
#include "types.h"
|
||||
#include "context.h"
|
||||
|
||||
struct certsig_s {
|
||||
|
||||
struct certsig_s
|
||||
{
|
||||
struct certsig_s *next;
|
||||
struct {
|
||||
unsigned int revoked:1 ;
|
||||
unsigned int expired:1 ;
|
||||
unsigned int invalid:1 ;
|
||||
struct
|
||||
{
|
||||
unsigned int revoked : 1;
|
||||
unsigned int expired : 1;
|
||||
unsigned int invalid : 1;
|
||||
unsigned int exportable : 1;
|
||||
} flags;
|
||||
char keyid[16+1];
|
||||
time_t timestamp; /* -1 for invalid, 0 for not available */
|
||||
time_t expires_at; /* 0 for does not expires */
|
||||
unsigned int algo;
|
||||
char keyid[16 + 1];
|
||||
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;
|
||||
unsigned int secret:1;
|
||||
struct {
|
||||
unsigned int revoked:1 ;
|
||||
unsigned int expired:1 ;
|
||||
unsigned int disabled:1 ;
|
||||
unsigned int invalid:1 ;
|
||||
unsigned int can_encrypt:1;
|
||||
unsigned int can_sign:1;
|
||||
unsigned int can_certify:1;
|
||||
struct
|
||||
{
|
||||
unsigned int revoked : 1;
|
||||
unsigned int expired : 1;
|
||||
unsigned int disabled : 1;
|
||||
unsigned int invalid : 1;
|
||||
unsigned int can_encrypt : 1;
|
||||
unsigned int can_sign : 1;
|
||||
unsigned int can_certify : 1;
|
||||
} flags;
|
||||
unsigned int key_algo;
|
||||
unsigned int key_len;
|
||||
char keyid[16+1];
|
||||
char *fingerprint; /* malloced hex digits */
|
||||
time_t timestamp; /* -1 for invalid, 0 for not available */
|
||||
time_t expires_at; /* 0 for does not expires */
|
||||
char keyid[16 + 1];
|
||||
char *fingerprint; /* Malloced hex digits. */
|
||||
time_t timestamp; /* -1 for invalid, 0 for not available. */
|
||||
time_t expires_at; /* 0 for does not expires. */
|
||||
};
|
||||
|
||||
struct gpgme_key_s {
|
||||
struct {
|
||||
unsigned int revoked:1 ;
|
||||
unsigned int expired:1 ;
|
||||
unsigned int disabled:1 ;
|
||||
unsigned int invalid:1 ;
|
||||
unsigned int can_encrypt:1;
|
||||
unsigned int can_sign:1;
|
||||
unsigned int can_certify:1;
|
||||
|
||||
struct gpgme_key_s
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned int revoked : 1;
|
||||
unsigned int expired : 1;
|
||||
unsigned int disabled : 1;
|
||||
unsigned int invalid : 1;
|
||||
unsigned int can_encrypt : 1;
|
||||
unsigned int can_sign : 1;
|
||||
unsigned int can_certify : 1;
|
||||
} gloflags;
|
||||
unsigned int ref_count;
|
||||
unsigned int secret:1;
|
||||
unsigned int x509:1;
|
||||
char *issuer_serial; /* malloced string used only with X.509 */
|
||||
char *issuer_name; /* ditto */
|
||||
char *chain_id; /* ditto */
|
||||
GpgmeValidity otrust; /* only used with OpenPGP */
|
||||
unsigned int secret : 1;
|
||||
unsigned int x509 : 1;
|
||||
char *issuer_serial; /* Malloced string used only with X.509. */
|
||||
char *issuer_name; /* Ditto. */
|
||||
char *chain_id; /* Ditto. */
|
||||
GpgmeValidity otrust; /* Only used with OpenPGP. */
|
||||
struct subkey_s keys;
|
||||
struct user_id_s *uids;
|
||||
struct user_id_s *last_uid;
|
||||
};
|
||||
|
||||
|
||||
void _gpgme_key_cache_init (void);
|
||||
void _gpgme_key_cache_add (GpgmeKey key);
|
||||
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_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 */
|
||||
|
670
gpgme/keylist.c
670
gpgme/keylist.c
@ -1,46 +1,45 @@
|
||||
/* keylist.c - key listing
|
||||
* Copyright (C) 2000 Werner Koch (dd9jn)
|
||||
* 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
|
||||
*/
|
||||
/* keylist.c - Listing keys.
|
||||
Copyright (C) 2000 Werner Koch (dd9jn)
|
||||
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 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>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "context.h"
|
||||
#include "ops.h"
|
||||
#include "key.h"
|
||||
|
||||
#define my_isdigit(a) ( (a) >='0' && (a) <= '9' )
|
||||
|
||||
|
||||
struct keylist_result_s
|
||||
{
|
||||
int truncated;
|
||||
GpgmeData xmlinfo;
|
||||
};
|
||||
|
||||
static void finish_key ( GpgmeCtx ctx );
|
||||
|
||||
|
||||
void
|
||||
_gpgme_release_keylist_result (KeylistResult result)
|
||||
@ -50,6 +49,7 @@ _gpgme_release_keylist_result (KeylistResult result)
|
||||
free (result);
|
||||
}
|
||||
|
||||
|
||||
/* Append some XML info. args is currently ignore but we might want
|
||||
to add more information in the future (like source of the
|
||||
keylisting. With args of NULL the XML structure is closed. */
|
||||
@ -78,15 +78,11 @@ append_xml_keylistinfo (GpgmeData *rdh, char *args)
|
||||
return;
|
||||
}
|
||||
|
||||
_gpgme_data_append_string (dh,
|
||||
" <keylisting>\n"
|
||||
" <truncated/>\n"
|
||||
);
|
||||
_gpgme_data_append_string (dh, " <keylisting>\n <truncated/>\n");
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
keylist_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args)
|
||||
{
|
||||
@ -117,192 +113,286 @@ keylist_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static time_t
|
||||
parse_timestamp (char *p)
|
||||
parse_timestamp (char *timestamp)
|
||||
{
|
||||
if (!*p)
|
||||
if (!*timestamp)
|
||||
return 0;
|
||||
|
||||
return (time_t)strtoul (p, NULL, 10);
|
||||
return (time_t) strtoul (timestamp, NULL, 10);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
set_mainkey_trust_info (GpgmeKey key, const char *s)
|
||||
set_mainkey_trust_info (GpgmeKey key, const char *src)
|
||||
{
|
||||
/* Look at letters and stop at the first digit. */
|
||||
for (; *s && !my_isdigit (*s); s++)
|
||||
while (*src && !isdigit (*src))
|
||||
{
|
||||
switch (*s)
|
||||
switch (*src)
|
||||
{
|
||||
case 'e': key->keys.flags.expired = 1; break;
|
||||
case 'r': key->keys.flags.revoked = 1; break;
|
||||
case 'd': key->keys.flags.disabled = 1; break;
|
||||
case 'i': key->keys.flags.invalid = 1; break;
|
||||
case 'e':
|
||||
key->keys.flags.expired = 1;
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
key->keys.flags.revoked = 1;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
key->keys.flags.disabled = 1;
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
key->keys.flags.invalid = 1;
|
||||
break;
|
||||
}
|
||||
src++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
set_userid_flags (GpgmeKey key, const char *s)
|
||||
set_userid_flags (GpgmeKey key, const char *src)
|
||||
{
|
||||
struct user_id_s *u = key->uids;
|
||||
|
||||
assert (u);
|
||||
while (u->next)
|
||||
u = u->next;
|
||||
struct user_id_s *uid = key->last_uid;
|
||||
|
||||
assert (uid);
|
||||
/* Look at letters and stop at the first digit. */
|
||||
for (; *s && !my_isdigit (*s); s++)
|
||||
while (*src && !isdigit (*src))
|
||||
{
|
||||
switch (*s)
|
||||
switch (*src)
|
||||
{
|
||||
case 'r': u->revoked = 1; break;
|
||||
case 'i': u->invalid = 1; break;
|
||||
case 'r':
|
||||
uid->revoked = 1;
|
||||
break;
|
||||
|
||||
case 'n': u->validity = GPGME_VALIDITY_NEVER; break;
|
||||
case 'm': u->validity = GPGME_VALIDITY_MARGINAL; break;
|
||||
case 'f': u->validity = GPGME_VALIDITY_FULL; break;
|
||||
case 'u': u->validity = GPGME_VALIDITY_ULTIMATE; break;
|
||||
case 'i':
|
||||
uid->invalid = 1;
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
uid->validity = GPGME_VALIDITY_NEVER;
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
uid->validity = GPGME_VALIDITY_MARGINAL;
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
uid->validity = GPGME_VALIDITY_FULL;
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
uid->validity = GPGME_VALIDITY_ULTIMATE;
|
||||
break;
|
||||
}
|
||||
src++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
set_subkey_trust_info (struct subkey_s *k, const char *s)
|
||||
set_subkey_trust_info (struct subkey_s *subkey, const char *src)
|
||||
{
|
||||
/* Look at letters and stop at the first digit. */
|
||||
for (; *s && !my_isdigit (*s); s++)
|
||||
while (*src && !isdigit (*src))
|
||||
{
|
||||
switch (*s)
|
||||
switch (*src)
|
||||
{
|
||||
case 'e': k->flags.expired = 1; break;
|
||||
case 'r': k->flags.revoked = 1; break;
|
||||
case 'd': k->flags.disabled = 1; break;
|
||||
case 'i': k->flags.invalid = 1; break;
|
||||
case 'e':
|
||||
subkey->flags.expired = 1;
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
subkey->flags.revoked = 1;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
subkey->flags.disabled = 1;
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
subkey->flags.invalid = 1;
|
||||
break;
|
||||
}
|
||||
src++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
set_mainkey_capability (GpgmeKey key, const char *s)
|
||||
set_mainkey_capability (GpgmeKey key, const char *src)
|
||||
{
|
||||
for (; *s ; s++)
|
||||
while (*src)
|
||||
{
|
||||
switch (*s)
|
||||
switch (*src)
|
||||
{
|
||||
case 'e': key->keys.flags.can_encrypt = 1; break;
|
||||
case 's': key->keys.flags.can_sign = 1; break;
|
||||
case 'c': key->keys.flags.can_certify = 1; break;
|
||||
case 'E': key->gloflags.can_encrypt = 1; break;
|
||||
case 'S': key->gloflags.can_sign = 1; break;
|
||||
case 'C': key->gloflags.can_certify = 1; break;
|
||||
case 'e':
|
||||
key->keys.flags.can_encrypt = 1;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
key->keys.flags.can_sign = 1;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
key->keys.flags.can_certify = 1;
|
||||
break;
|
||||
|
||||
case 'E':
|
||||
key->gloflags.can_encrypt = 1;
|
||||
break;
|
||||
|
||||
case 'S':
|
||||
key->gloflags.can_sign = 1;
|
||||
break;
|
||||
|
||||
case 'C':
|
||||
key->gloflags.can_certify = 1;
|
||||
break;
|
||||
}
|
||||
src++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
set_subkey_capability ( struct subkey_s *k, const char *s)
|
||||
set_subkey_capability (struct subkey_s *subkey, const char *src)
|
||||
{
|
||||
for (; *s; s++)
|
||||
while (*src)
|
||||
{
|
||||
switch (*s)
|
||||
switch (*src)
|
||||
{
|
||||
case 'e': k->flags.can_encrypt = 1; break;
|
||||
case 's': k->flags.can_sign = 1; break;
|
||||
case 'c': k->flags.can_certify = 1; break;
|
||||
case 'e':
|
||||
subkey->flags.can_encrypt = 1;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
subkey->flags.can_sign = 1;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
subkey->flags.can_certify = 1;
|
||||
break;
|
||||
}
|
||||
src++;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
set_ownertrust (GpgmeKey key, const char *s)
|
||||
set_ownertrust (GpgmeKey key, const char *src)
|
||||
{
|
||||
/* Look at letters and stop at the first digit. */
|
||||
for (; *s && !my_isdigit (*s); s++)
|
||||
while (*src && !isdigit (*src))
|
||||
{
|
||||
switch (*s)
|
||||
switch (*src)
|
||||
{
|
||||
case 'n': key->otrust = GPGME_VALIDITY_NEVER; break;
|
||||
case 'm': key->otrust = GPGME_VALIDITY_MARGINAL; break;
|
||||
case 'f': key->otrust = GPGME_VALIDITY_FULL; break;
|
||||
case 'u': key->otrust = GPGME_VALIDITY_ULTIMATE; break;
|
||||
default : key->otrust = GPGME_VALIDITY_UNKNOWN; break;
|
||||
case 'n':
|
||||
key->otrust = GPGME_VALIDITY_NEVER;
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
key->otrust = GPGME_VALIDITY_MARGINAL;
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
key->otrust = GPGME_VALIDITY_FULL;
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
key->otrust = GPGME_VALIDITY_ULTIMATE;
|
||||
break;
|
||||
|
||||
default:
|
||||
key->otrust = GPGME_VALIDITY_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
src++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* We have read an entire key into ctx->tmp_key and should now finish
|
||||
it. It is assumed that this releases ctx->tmp_key. */
|
||||
static void
|
||||
finish_key (GpgmeCtx ctx)
|
||||
{
|
||||
GpgmeKey key = ctx->tmp_key;
|
||||
|
||||
ctx->tmp_key = NULL;
|
||||
|
||||
if (key)
|
||||
_gpgme_engine_io_event (ctx->engine, GPGME_EVENT_NEXT_KEY, key);
|
||||
}
|
||||
|
||||
|
||||
/* Note: We are allowed to modify LINE. */
|
||||
static void
|
||||
keylist_colon_handler (GpgmeCtx ctx, char *line)
|
||||
{
|
||||
char *p, *pend;
|
||||
int field = 0;
|
||||
enum
|
||||
{
|
||||
RT_NONE, RT_SIG, RT_UID, RT_SUB, RT_PUB, RT_FPR, RT_SSB, RT_SEC,
|
||||
RT_CRT, RT_CRS
|
||||
RT_CRT, RT_CRS, RT_REV
|
||||
}
|
||||
rectype = RT_NONE;
|
||||
#define NR_FIELDS 13
|
||||
char *field[NR_FIELDS];
|
||||
int fields = 0;
|
||||
GpgmeKey key = ctx->tmp_key;
|
||||
int i;
|
||||
const char *trust_info = NULL;
|
||||
struct subkey_s *sk = NULL;
|
||||
struct subkey_s *subkey = NULL;
|
||||
struct certsig_s *certsig = NULL;
|
||||
|
||||
DEBUG3 ("keylist_colon_handler ctx = %p, key = %p, line = %s\n",
|
||||
ctx, key, line ? line : "(null)");
|
||||
|
||||
DEBUG3 ("keylist_colon_handler ctx=%p, key=%p, line=%s\n", ctx, key,
|
||||
line? line: "(null)");
|
||||
if (ctx->error)
|
||||
return;
|
||||
|
||||
if (!line)
|
||||
{
|
||||
/* EOF */
|
||||
/* End Of File. */
|
||||
finish_key (ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
for (p = line; p; p = pend)
|
||||
while (line && fields < NR_FIELDS)
|
||||
{
|
||||
field++;
|
||||
pend = strchr (p, ':');
|
||||
if (pend)
|
||||
*pend++ = 0;
|
||||
|
||||
if (field == 1)
|
||||
{
|
||||
if (!strcmp (p, "sig"))
|
||||
rectype = RT_SIG;
|
||||
else if (!strcmp (p, "uid") && key)
|
||||
{
|
||||
rectype = RT_UID;
|
||||
key = ctx->tmp_key;
|
||||
field[fields++] = line;
|
||||
line = strchr (line, ':');
|
||||
if (line)
|
||||
*(line++) = '\0';
|
||||
}
|
||||
else if (!strcmp (p, "sub") && key)
|
||||
|
||||
if (!strcmp (field[0], "sig"))
|
||||
rectype = RT_SIG;
|
||||
else if (!strcmp (field[0], "rev"))
|
||||
rectype = RT_REV;
|
||||
else if (!strcmp (field[0], "uid") && key)
|
||||
rectype = RT_UID;
|
||||
else if (!strcmp (field[0], "sub") && key)
|
||||
{
|
||||
/* Start a new subkey. */
|
||||
rectype = RT_SUB;
|
||||
if (!(sk = _gpgme_key_add_subkey (key)))
|
||||
if (!(subkey = _gpgme_key_add_subkey (key)))
|
||||
{
|
||||
ctx->error = mk_error (Out_Of_Core);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (!strcmp (p, "ssb") && key)
|
||||
else if (!strcmp (field[0], "ssb") && key)
|
||||
{
|
||||
/* Start a new secret subkey. */
|
||||
rectype = RT_SSB;
|
||||
if (!(sk = _gpgme_key_add_secret_subkey (key)))
|
||||
if (!(subkey = _gpgme_key_add_secret_subkey (key)))
|
||||
{
|
||||
ctx->error = mk_error (Out_Of_Core);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (!strcmp (p, "pub"))
|
||||
else if (!strcmp (field[0], "pub"))
|
||||
{
|
||||
/* Start a new keyblock. */
|
||||
if (_gpgme_key_new (&key))
|
||||
@ -316,7 +406,7 @@ keylist_colon_handler (GpgmeCtx ctx, char *line)
|
||||
assert (!ctx->tmp_key);
|
||||
ctx->tmp_key = key;
|
||||
}
|
||||
else if (!strcmp (p, "sec"))
|
||||
else if (!strcmp (field[0], "sec"))
|
||||
{
|
||||
/* Start a new keyblock, */
|
||||
if (_gpgme_key_new_secret (&key))
|
||||
@ -330,7 +420,7 @@ keylist_colon_handler (GpgmeCtx ctx, char *line)
|
||||
assert (!ctx->tmp_key);
|
||||
ctx->tmp_key = key;
|
||||
}
|
||||
else if (!strcmp (p, "crt"))
|
||||
else if (!strcmp (field[0], "crt"))
|
||||
{
|
||||
/* Start a new certificate. */
|
||||
if (_gpgme_key_new (&key))
|
||||
@ -345,7 +435,7 @@ keylist_colon_handler (GpgmeCtx ctx, char *line)
|
||||
assert (!ctx->tmp_key);
|
||||
ctx->tmp_key = key;
|
||||
}
|
||||
else if (!strcmp (p, "crs"))
|
||||
else if (!strcmp (field[0], "crs"))
|
||||
{
|
||||
/* Start a new certificate. */
|
||||
if (_gpgme_key_new_secret (&key))
|
||||
@ -360,171 +450,240 @@ keylist_colon_handler (GpgmeCtx ctx, char *line)
|
||||
assert (!ctx->tmp_key);
|
||||
ctx->tmp_key = key;
|
||||
}
|
||||
else if (!strcmp (p, "fpr") && key)
|
||||
else if (!strcmp (field[0], "fpr") && key)
|
||||
rectype = RT_FPR;
|
||||
else
|
||||
rectype = RT_NONE;
|
||||
}
|
||||
else if (rectype == RT_PUB || rectype == RT_SEC
|
||||
|| rectype == RT_CRT || rectype == RT_CRS)
|
||||
|
||||
/* Only look at signatures immediately following a user ID. For
|
||||
this, clear the user ID pointer when encountering anything but a
|
||||
signature. */
|
||||
if (rectype != RT_SIG && rectype != RT_REV)
|
||||
ctx->tmp_uid = NULL;
|
||||
|
||||
switch (rectype)
|
||||
{
|
||||
switch (field)
|
||||
case RT_CRT:
|
||||
case RT_CRS:
|
||||
/* Field 8 has the X.509 serial number. */
|
||||
if (fields >= 8)
|
||||
{
|
||||
case 2: /* trust info */
|
||||
trust_info = p;
|
||||
set_mainkey_trust_info (key, trust_info);
|
||||
break;
|
||||
case 3: /* key length */
|
||||
i = atoi (p);
|
||||
if (i > 1) /* ignore invalid values */
|
||||
key->keys.key_len = i;
|
||||
break;
|
||||
case 4: /* pubkey algo */
|
||||
i = atoi (p);
|
||||
if (i >= 1 && i < 128)
|
||||
key->keys.key_algo = i;
|
||||
break;
|
||||
case 5: /* long keyid */
|
||||
if (strlen (p) == DIM(key->keys.keyid) - 1)
|
||||
strcpy (key->keys.keyid, p);
|
||||
break;
|
||||
case 6: /* timestamp (seconds) */
|
||||
key->keys.timestamp = parse_timestamp (p);
|
||||
break;
|
||||
case 7: /* expiration time (seconds) */
|
||||
key->keys.expires_at = parse_timestamp (p);
|
||||
break;
|
||||
case 8: /* X.509 serial number */
|
||||
if (rectype == RT_CRT || rectype == RT_CRS)
|
||||
{
|
||||
key->issuer_serial = strdup (p);
|
||||
key->issuer_serial = strdup (field[7]);
|
||||
if (!key->issuer_serial)
|
||||
ctx->error = mk_error (Out_Of_Core);
|
||||
}
|
||||
break;
|
||||
case 9: /* ownertrust */
|
||||
set_ownertrust (key, p);
|
||||
break;
|
||||
case 10:
|
||||
/* Not used for gpg due to --fixed-list-mode option but
|
||||
GPGSM stores the issuer name. */
|
||||
if (rectype == RT_CRT || rectype == RT_CRS)
|
||||
if (_gpgme_decode_c_string (p, &key->issuer_name))
|
||||
|
||||
/* Field 10 is not used for gpg due to --fixed-list-mode option
|
||||
but GPGSM stores the issuer name. */
|
||||
if (fields >= 10 && _gpgme_decode_c_string (field[9],
|
||||
&key->issuer_name, 0))
|
||||
ctx->error = mk_error (Out_Of_Core);
|
||||
break;
|
||||
case 11: /* signature class */
|
||||
break;
|
||||
case 12: /* capabilities */
|
||||
set_mainkey_capability (key, p);
|
||||
break;
|
||||
case 13:
|
||||
pend = NULL; /* we can stop here */
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if ((rectype == RT_SUB || rectype== RT_SSB) && sk)
|
||||
/* Fall through! */
|
||||
|
||||
case RT_PUB:
|
||||
case RT_SEC:
|
||||
/* Field 2 has the trust info. */
|
||||
if (fields >= 2)
|
||||
set_mainkey_trust_info (key, field[1]);
|
||||
|
||||
/* Field 3 has the key length. */
|
||||
if (fields >= 3)
|
||||
{
|
||||
switch (field)
|
||||
int i = atoi (field[2]);
|
||||
/* Ignore invalid values. */
|
||||
if (i > 1)
|
||||
key->keys.key_len = i;
|
||||
}
|
||||
|
||||
/* Field 4 has the public key algorithm. */
|
||||
if (fields >= 4)
|
||||
{
|
||||
case 2: /* trust info */
|
||||
set_subkey_trust_info (sk, p);
|
||||
break;
|
||||
case 3: /* key length */
|
||||
i = atoi (p);
|
||||
if (i > 1) /* ignore invalid values */
|
||||
sk->key_len = i;
|
||||
break;
|
||||
case 4: /* pubkey algo */
|
||||
i = atoi (p);
|
||||
int i = atoi (field[3]);
|
||||
if (i >= 1 && i < 128)
|
||||
sk->key_algo = i;
|
||||
break;
|
||||
case 5: /* long keyid */
|
||||
if (strlen (p) == DIM(sk->keyid) - 1)
|
||||
strcpy (sk->keyid, p);
|
||||
break;
|
||||
case 6: /* timestamp (seconds) */
|
||||
sk->timestamp = parse_timestamp (p);
|
||||
break;
|
||||
case 7: /* expiration time (seconds) */
|
||||
sk->expires_at = parse_timestamp (p);
|
||||
break;
|
||||
case 8: /* reserved (LID) */
|
||||
break;
|
||||
case 9: /* ownertrust */
|
||||
break;
|
||||
case 10:/* user ID n/a for a subkey */
|
||||
break;
|
||||
case 11: /* signature class */
|
||||
break;
|
||||
case 12: /* capability */
|
||||
set_subkey_capability (sk, p);
|
||||
break;
|
||||
case 13:
|
||||
pend = NULL; /* we can stop here */
|
||||
break;
|
||||
key->keys.key_algo = i;
|
||||
}
|
||||
}
|
||||
else if (rectype == RT_UID)
|
||||
{
|
||||
switch (field)
|
||||
{
|
||||
case 2: /* trust info */
|
||||
trust_info = p; /*save for later */
|
||||
|
||||
/* Field 5 has the long keyid. */
|
||||
if (fields >= 5 && strlen (field[4]) == DIM(key->keys.keyid) - 1)
|
||||
strcpy (key->keys.keyid, field[4]);
|
||||
|
||||
/* Field 6 has the timestamp (seconds). */
|
||||
if (fields >= 6)
|
||||
key->keys.timestamp = parse_timestamp (field[5]);
|
||||
|
||||
/* Field 7 has the expiration time (seconds). */
|
||||
if (fields >= 7)
|
||||
key->keys.expires_at = parse_timestamp (field[6]);
|
||||
|
||||
/* Field 9 has the ownertrust. */
|
||||
if (fields >= 9)
|
||||
set_ownertrust (key, field[8]);
|
||||
|
||||
/* Field 11 has the signature class. */
|
||||
|
||||
/* Field 12 has the capabilities. */
|
||||
if (fields >= 12)
|
||||
set_mainkey_capability (key, field[11]);
|
||||
break;
|
||||
case 10: /* user ID */
|
||||
if (_gpgme_key_append_name (key, p))
|
||||
/* The only kind of error we can get*/
|
||||
|
||||
case RT_SUB:
|
||||
case RT_SSB:
|
||||
/* Field 2 has the trust info. */
|
||||
if (fields >= 2)
|
||||
set_subkey_trust_info (subkey, field[1]);
|
||||
|
||||
/* Field 3 has the key length. */
|
||||
if (fields >= 3)
|
||||
{
|
||||
int i = atoi (field[2]);
|
||||
/* Ignore invalid values. */
|
||||
if (i > 1)
|
||||
subkey->key_len = i;
|
||||
}
|
||||
|
||||
/* Field 4 has the public key algorithm. */
|
||||
if (fields >= 4)
|
||||
{
|
||||
int i = atoi (field[3]);
|
||||
if (i >= 1 && i < 128)
|
||||
subkey->key_algo = i;
|
||||
}
|
||||
|
||||
/* Field 5 has the long keyid. */
|
||||
if (fields >= 5 && strlen (field[4]) == DIM(subkey->keyid) - 1)
|
||||
strcpy (subkey->keyid, field[4]);
|
||||
|
||||
/* Field 6 has the timestamp (seconds). */
|
||||
if (fields >= 6)
|
||||
subkey->timestamp = parse_timestamp (field[5]);
|
||||
|
||||
/* Field 7 has the expiration time (seconds). */
|
||||
if (fields >= 7)
|
||||
subkey->expires_at = parse_timestamp (field[6]);
|
||||
|
||||
/* Field 8 is reserved (LID). */
|
||||
/* Field 9 has the ownertrust. */
|
||||
/* Field 10, the user ID, is n/a for a subkey. */
|
||||
|
||||
/* Field 11 has the signature class. */
|
||||
|
||||
/* Field 12 has the capabilities. */
|
||||
if (fields >= 12)
|
||||
set_subkey_capability (subkey, field[11]);
|
||||
break;
|
||||
|
||||
case RT_UID:
|
||||
/* Field 2 has the trust info, and field 10 has the user ID. */
|
||||
if (fields >= 10)
|
||||
{
|
||||
if (_gpgme_key_append_name (key, field[9]))
|
||||
ctx->error = mk_error (Out_Of_Core);
|
||||
else
|
||||
{
|
||||
if (trust_info)
|
||||
set_userid_flags (key, trust_info);
|
||||
if (field[1])
|
||||
set_userid_flags (key, field[1]);
|
||||
ctx->tmp_uid = key->last_uid;
|
||||
}
|
||||
}
|
||||
pend = NULL; /* we can stop here */
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (rectype == RT_FPR)
|
||||
|
||||
case RT_FPR:
|
||||
/* Field 10 has the fingerprint (take only the first one). */
|
||||
if (fields >= 10 && !key->keys.fingerprint && field[9] && *field[9])
|
||||
{
|
||||
switch (field)
|
||||
{
|
||||
case 10: /* fingerprint (take only the first one)*/
|
||||
if (!key->keys.fingerprint && *p)
|
||||
{
|
||||
key->keys.fingerprint = strdup (p);
|
||||
key->keys.fingerprint = strdup (field[9]);
|
||||
if (!key->keys.fingerprint)
|
||||
ctx->error = mk_error (Out_Of_Core);
|
||||
}
|
||||
break;
|
||||
case 13: /* gpgsm chain ID (take only the first one)*/
|
||||
if (!key->chain_id && *p)
|
||||
|
||||
/* Field 13 has the gpgsm chain ID (take only the first one). */
|
||||
if (fields >= 13 && !key->chain_id && *field[12])
|
||||
{
|
||||
key->chain_id = strdup (p);
|
||||
key->chain_id = strdup (field[12]);
|
||||
if (!key->chain_id)
|
||||
ctx->error = mk_error (Out_Of_Core);
|
||||
}
|
||||
pend = NULL; /* that is all we want */
|
||||
break;
|
||||
|
||||
case RT_SIG:
|
||||
case RT_REV:
|
||||
if (!ctx->tmp_uid)
|
||||
return;
|
||||
|
||||
/* Start a new (revoked) signature. */
|
||||
assert (ctx->tmp_uid == key->last_uid);
|
||||
certsig = _gpgme_key_add_certsig (key, (fields >= 10) ? field[9] : NULL);
|
||||
if (!certsig)
|
||||
{
|
||||
ctx->error = mk_error (Out_Of_Core);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Field 2 has the calculated trust ('!', '-', '?', '%'). */
|
||||
if (fields >= 2)
|
||||
switch (field[1][0])
|
||||
{
|
||||
case '!':
|
||||
certsig->sig_stat = GPGME_SIG_STAT_GOOD;
|
||||
break;
|
||||
|
||||
case '-':
|
||||
certsig->sig_stat = GPGME_SIG_STAT_BAD;
|
||||
break;
|
||||
|
||||
case '?':
|
||||
certsig->sig_stat = GPGME_SIG_STAT_NOKEY;
|
||||
break;
|
||||
|
||||
case '%':
|
||||
certsig->sig_stat = GPGME_SIG_STAT_ERROR;
|
||||
break;
|
||||
|
||||
default:
|
||||
certsig->sig_stat = GPGME_SIG_STAT_NONE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Field 4 has the public key algorithm. */
|
||||
if (fields >= 4)
|
||||
{
|
||||
int i = atoi (field[3]);
|
||||
if (i >= 1 && i < 128)
|
||||
certsig->algo = i;
|
||||
}
|
||||
|
||||
/* Field 5 has the long keyid. */
|
||||
if (fields >= 5 && strlen (field[4]) == DIM(certsig->keyid) - 1)
|
||||
strcpy (certsig->keyid, field[4]);
|
||||
|
||||
/* Field 6 has the timestamp (seconds). */
|
||||
if (fields >= 6)
|
||||
certsig->timestamp = parse_timestamp (field[5]);
|
||||
|
||||
/* Field 7 has the expiration time (seconds). */
|
||||
if (fields >= 7)
|
||||
certsig->expires_at = parse_timestamp (field[6]);
|
||||
|
||||
/* Field 11 has the signature class (eg, 0x30 means revoked). */
|
||||
if (fields >= 11)
|
||||
if (field[10][0] && field[10][1])
|
||||
{
|
||||
int class = _gpgme_hextobyte (field[10]);
|
||||
if (class >= 0)
|
||||
{
|
||||
certsig->sig_class = class;
|
||||
if (class == 0x30)
|
||||
certsig->flags.revoked = 1;
|
||||
}
|
||||
}
|
||||
if (field[10][2] == 'x')
|
||||
certsig->flags.exportable = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
/*
|
||||
* We have read an entire key into ctx->tmp_key and should now finish
|
||||
* it. It is assumed that this releases ctx->tmp_key.
|
||||
*/
|
||||
static void
|
||||
finish_key (GpgmeCtx ctx)
|
||||
{
|
||||
GpgmeKey key = ctx->tmp_key;
|
||||
|
||||
ctx->tmp_key = NULL;
|
||||
|
||||
if (key)
|
||||
_gpgme_engine_io_event (ctx->engine, GPGME_EVENT_NEXT_KEY, key);
|
||||
case RT_NONE:
|
||||
/* Unknown record. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -593,9 +752,9 @@ gpgme_op_keylist_start (GpgmeCtx ctx, const char *pattern, int secret_only)
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
/* We don't want to use the verbose mode as this will also print
|
||||
the key signatures which is in most cases not needed and furthermore we
|
||||
just ignore those lines - This should speed up things */
|
||||
/* We don't want to use the verbose mode as this will also print the
|
||||
key signatures which is in most cases not needed and furthermore
|
||||
we just ignore those lines - This should speed up things. */
|
||||
_gpgme_engine_set_verbosity (ctx->engine, 0);
|
||||
|
||||
err = _gpgme_engine_op_keylist (ctx->engine, pattern, secret_only,
|
||||
@ -647,15 +806,16 @@ gpgme_op_keylist_ext_start (GpgmeCtx ctx, const char *pattern[],
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
/* We don't want to use the verbose mode as this will also print
|
||||
the key signatures which is in most cases not needed and furthermore we
|
||||
just ignore those lines - This should speed up things */
|
||||
/* We don't want to use the verbose mode as this will also print the
|
||||
key signatures which is in most cases not needed and furthermore
|
||||
we just ignore those lines - This should speed up things. */
|
||||
_gpgme_engine_set_verbosity (ctx->engine, 0);
|
||||
|
||||
err = _gpgme_engine_op_keylist_ext (ctx->engine, pattern, secret_only,
|
||||
reserved, ctx->keylist_mode);
|
||||
|
||||
if (!err) /* And kick off the process. */
|
||||
/* And kick off the process. */
|
||||
if (!err)
|
||||
err = _gpgme_engine_start (ctx->engine, ctx);
|
||||
|
||||
leave:
|
||||
|
@ -1486,10 +1486,9 @@ gpg_keylist (void *engine, const char *pattern, int secret_only,
|
||||
if (!err)
|
||||
err = add_arg (gpg, "--with-fingerprint");
|
||||
if (!err)
|
||||
err = add_arg (gpg, (keylist_mode & GPGME_KEYLIST_MODE_SIGS) ?
|
||||
"--check-sigs" :
|
||||
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. */
|
||||
if (!err)
|
||||
@ -1519,7 +1518,9 @@ gpg_keylist_ext (void *engine, const char *pattern[], int secret_only,
|
||||
if (!err)
|
||||
err = add_arg (gpg, "--with-fingerprint");
|
||||
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. */
|
||||
if (!err)
|
||||
|
@ -85,7 +85,13 @@ FILE *fopencookie (void *cookie, const char *opentype,
|
||||
|
||||
|
||||
/*-- 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);
|
||||
|
||||
#endif /* UTIL_H */
|
||||
|
@ -643,42 +643,20 @@ gpgme_get_sig_ulong_attr (GpgmeCtx c, int idx, GpgmeAttr what, int reserved)
|
||||
* indicate that there are no more signatures.
|
||||
**/
|
||||
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;
|
||||
GpgmeError err = 0;
|
||||
|
||||
if (!c || !r_key)
|
||||
if (!ctx || !r_key)
|
||||
return mk_error (Invalid_Value);
|
||||
if (c->pending || !c->result.verify)
|
||||
if (ctx->pending || !ctx->result.verify)
|
||||
return mk_error (Busy);
|
||||
|
||||
for (result = c->result.verify;
|
||||
for (result = ctx->result.verify;
|
||||
result && idx > 0; result = result->next, idx--)
|
||||
;
|
||||
if (!result)
|
||||
return mk_error (EOF);
|
||||
|
||||
if (strlen(result->fpr) < 16) /* We have at least a key ID. */
|
||||
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;
|
||||
return gpgme_get_key (ctx, result->fpr, r_key, 0, 0);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user