Blame src/key.c

Packit d7e8d0
/* key.c - Key objects.
Packit Service 30b792
 * Copyright (C) 2000 Werner Koch (dd9jn)
Packit Service 30b792
 * Copyright (C) 2001, 2002, 2003, 2004 g10 Code GmbH
Packit Service 30b792
 *
Packit Service 30b792
 * This file is part of GPGME.
Packit Service 30b792
 *
Packit Service 30b792
 * GPGME is free software; you can redistribute it and/or modify it
Packit Service 30b792
 * under the terms of the GNU Lesser General Public License as
Packit Service 30b792
 * published by the Free Software Foundation; either version 2.1 of
Packit Service 30b792
 * the License, or (at your option) any later version.
Packit Service 30b792
 *
Packit Service 30b792
 * GPGME is distributed in the hope that it will be useful, but
Packit Service 30b792
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 30b792
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 30b792
 * Lesser General Public License for more details.
Packit Service 30b792
 *
Packit Service 30b792
 * You should have received a copy of the GNU Lesser General Public
Packit Service 30b792
 * License along with this program; if not, see <https://gnu.org/licenses/>.
Packit Service 30b792
 * SPDX-License-Identifier: LGPL-2.1-or-later
Packit Service 30b792
 */
Packit d7e8d0
Packit d7e8d0
#if HAVE_CONFIG_H
Packit d7e8d0
#include <config.h>
Packit d7e8d0
#endif
Packit d7e8d0
#include <stdlib.h>
Packit d7e8d0
#include <string.h>
Packit d7e8d0
#include <assert.h>
Packit d7e8d0
#include <errno.h>
Packit d7e8d0
Packit d7e8d0
#include "util.h"
Packit d7e8d0
#include "ops.h"
Packit d7e8d0
#include "sema.h"
Packit d7e8d0
#include "debug.h"
Packit d7e8d0
#include "mbox-util.h"
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0

Packit d7e8d0
/* Protects all reference counters in keys.  All other accesses to a
Packit d7e8d0
   key are read only.  */
Packit d7e8d0
DEFINE_STATIC_LOCK (key_ref_lock);
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
/* Create a new key.  */
Packit d7e8d0
gpgme_error_t
Packit d7e8d0
_gpgme_key_new (gpgme_key_t *r_key)
Packit d7e8d0
{
Packit d7e8d0
  gpgme_key_t key;
Packit d7e8d0
Packit d7e8d0
  key = calloc (1, sizeof *key);
Packit d7e8d0
  if (!key)
Packit d7e8d0
    return gpg_error_from_syserror ();
Packit d7e8d0
  key->_refs = 1;
Packit d7e8d0
Packit d7e8d0
  *r_key = key;
Packit d7e8d0
  return 0;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
gpgme_error_t
Packit d7e8d0
_gpgme_key_add_subkey (gpgme_key_t key, gpgme_subkey_t *r_subkey)
Packit d7e8d0
{
Packit d7e8d0
  gpgme_subkey_t subkey;
Packit d7e8d0
Packit d7e8d0
  subkey = calloc (1, sizeof *subkey);
Packit d7e8d0
  if (!subkey)
Packit d7e8d0
    return gpg_error_from_syserror ();
Packit d7e8d0
  subkey->keyid = subkey->_keyid;
Packit d7e8d0
  subkey->_keyid[16] = '\0';
Packit d7e8d0
Packit d7e8d0
  if (!key->subkeys)
Packit d7e8d0
    key->subkeys = subkey;
Packit d7e8d0
  if (key->_last_subkey)
Packit d7e8d0
    key->_last_subkey->next = subkey;
Packit d7e8d0
  key->_last_subkey = subkey;
Packit d7e8d0
Packit d7e8d0
  *r_subkey = subkey;
Packit d7e8d0
  return 0;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
static char *
Packit d7e8d0
set_user_id_part (char *tail, const char *buf, size_t len)
Packit d7e8d0
{
Packit d7e8d0
  while (len && (buf[len - 1] == ' ' || buf[len - 1] == '\t'))
Packit d7e8d0
    len--;
Packit d7e8d0
  for (; len; len--)
Packit d7e8d0
    *tail++ = *buf++;
Packit d7e8d0
  *tail++ = 0;
Packit d7e8d0
  return tail;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
static void
Packit d7e8d0
parse_user_id (char *src, char **name, char **email,
Packit d7e8d0
	       char **comment, char *tail)
Packit d7e8d0
{
Packit d7e8d0
  const char *start = NULL;
Packit d7e8d0
  int in_name = 0;
Packit d7e8d0
  int in_email = 0;
Packit d7e8d0
  int in_comment = 0;
Packit d7e8d0
Packit d7e8d0
  while (*src)
Packit d7e8d0
    {
Packit d7e8d0
      if (in_email)
Packit d7e8d0
	{
Packit d7e8d0
	  if (*src == '<')
Packit d7e8d0
	    /* Not legal but anyway.  */
Packit d7e8d0
	    in_email++;
Packit d7e8d0
	  else if (*src == '>')
Packit d7e8d0
	    {
Packit d7e8d0
	      if (!--in_email && !*email)
Packit d7e8d0
		{
Packit d7e8d0
		  *email = tail;
Packit d7e8d0
		  tail = set_user_id_part (tail, start, src - start);
Packit d7e8d0
		}
Packit d7e8d0
	    }
Packit d7e8d0
	}
Packit d7e8d0
      else if (in_comment)
Packit d7e8d0
	{
Packit d7e8d0
	  if (*src == '(')
Packit d7e8d0
	    in_comment++;
Packit d7e8d0
	  else if (*src == ')')
Packit d7e8d0
	    {
Packit d7e8d0
	      if (!--in_comment && !*comment)
Packit d7e8d0
		{
Packit d7e8d0
		  *comment = tail;
Packit d7e8d0
		  tail = set_user_id_part (tail, start, src - start);
Packit d7e8d0
		}
Packit d7e8d0
	    }
Packit d7e8d0
	}
Packit d7e8d0
      else if (*src == '<')
Packit d7e8d0
	{
Packit d7e8d0
	  if (in_name)
Packit d7e8d0
	    {
Packit d7e8d0
	      if (!*name)
Packit d7e8d0
		{
Packit d7e8d0
		  *name = tail;
Packit d7e8d0
		  tail = set_user_id_part (tail, start, src - start);
Packit d7e8d0
		}
Packit d7e8d0
	      in_name = 0;
Packit d7e8d0
	    }
Packit d7e8d0
	  in_email = 1;
Packit d7e8d0
	  start = src + 1;
Packit d7e8d0
	}
Packit d7e8d0
      else if (*src == '(')
Packit d7e8d0
	{
Packit d7e8d0
	  if (in_name)
Packit d7e8d0
	    {
Packit d7e8d0
	      if (!*name)
Packit d7e8d0
		{
Packit d7e8d0
		  *name = tail;
Packit d7e8d0
		  tail = set_user_id_part (tail, start, src - start);
Packit d7e8d0
		}
Packit d7e8d0
	      in_name = 0;
Packit d7e8d0
	    }
Packit d7e8d0
	  in_comment = 1;
Packit d7e8d0
	  start = src + 1;
Packit d7e8d0
	}
Packit d7e8d0
      else if (!in_name && *src != ' ' && *src != '\t')
Packit d7e8d0
	{
Packit d7e8d0
	  in_name = 1;
Packit d7e8d0
	  start = src;
Packit d7e8d0
	}
Packit d7e8d0
      src++;
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  if (in_name)
Packit d7e8d0
    {
Packit d7e8d0
      if (!*name)
Packit d7e8d0
	{
Packit d7e8d0
	  *name = tail;
Packit d7e8d0
	  tail = set_user_id_part (tail, start, src - start);
Packit d7e8d0
	}
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  /* Let unused parts point to an EOS.  */
Packit d7e8d0
  tail--;
Packit d7e8d0
  if (!*name)
Packit d7e8d0
    *name = tail;
Packit d7e8d0
  if (!*email)
Packit d7e8d0
    *email = tail;
Packit d7e8d0
  if (!*comment)
Packit d7e8d0
    *comment = tail;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
static void
Packit d7e8d0
parse_x509_user_id (char *src, char **name, char **email,
Packit d7e8d0
		    char **comment, char *tail)
Packit d7e8d0
{
Packit d7e8d0
  if (*src == '<' && src[strlen (src) - 1] == '>')
Packit d7e8d0
    *email = src;
Packit d7e8d0
Packit d7e8d0
  /* Let unused parts point to an EOS.  */
Packit d7e8d0
  tail--;
Packit d7e8d0
  if (!*name)
Packit d7e8d0
    *name = tail;
Packit d7e8d0
  if (!*email)
Packit d7e8d0
    *email = tail;
Packit d7e8d0
  if (!*comment)
Packit d7e8d0
    *comment = tail;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
/* Take a name from the --with-colon listing, remove certain escape
Packit d7e8d0
   sequences sequences and put it into the list of UIDs.  */
Packit d7e8d0
gpgme_error_t
Packit d7e8d0
_gpgme_key_append_name (gpgme_key_t key, const char *src, int convert)
Packit d7e8d0
{
Packit d7e8d0
  gpgme_user_id_t uid;
Packit d7e8d0
  char *dst;
Packit d7e8d0
  int src_len = strlen (src);
Packit d7e8d0
Packit d7e8d0
  assert (key);
Packit d7e8d0
  /* We can malloc a buffer of the same length, because the converted
Packit d7e8d0
     string will never be larger. Actually we allocate it twice the
Packit d7e8d0
     size, so that we are able to store the parsed stuff there too.  */
Packit d7e8d0
  uid = malloc (sizeof (*uid) + 2 * src_len + 3);
Packit d7e8d0
  if (!uid)
Packit d7e8d0
    return gpg_error_from_syserror ();
Packit d7e8d0
  memset (uid, 0, sizeof *uid);
Packit d7e8d0
Packit d7e8d0
  uid->uid = ((char *) uid) + sizeof (*uid);
Packit d7e8d0
  dst = uid->uid;
Packit d7e8d0
  if (convert)
Packit d7e8d0
    _gpgme_decode_c_string (src, &dst, src_len + 1);
Packit d7e8d0
  else
Packit d7e8d0
    memcpy (dst, src, src_len + 1);
Packit d7e8d0
Packit d7e8d0
  dst += strlen (dst) + 1;
Packit d7e8d0
  if (key->protocol == GPGME_PROTOCOL_CMS)
Packit d7e8d0
    parse_x509_user_id (uid->uid, &uid->name, &uid->email,
Packit d7e8d0
			&uid->comment, dst);
Packit d7e8d0
  else
Packit d7e8d0
    parse_user_id (uid->uid, &uid->name, &uid->email,
Packit d7e8d0
		   &uid->comment, dst);
Packit d7e8d0
Packit d7e8d0
  uid->address = _gpgme_mailbox_from_userid (uid->uid);
Packit d7e8d0
  if ((!uid->email || !*uid->email) && uid->address && uid->name
Packit d7e8d0
      && !strcmp (uid->name, uid->address))
Packit d7e8d0
    {
Packit d7e8d0
      /* Name and address are the same. This is a mailbox only key.
Packit d7e8d0
         Use address as email and remove name. */
Packit d7e8d0
      *uid->name = '\0';
Packit d7e8d0
      uid->email = uid->address;
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  if (!key->uids)
Packit d7e8d0
    key->uids = uid;
Packit d7e8d0
  if (key->_last_uid)
Packit d7e8d0
    key->_last_uid->next = uid;
Packit d7e8d0
  key->_last_uid = uid;
Packit d7e8d0
Packit d7e8d0
  return 0;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
gpgme_key_sig_t
Packit d7e8d0
_gpgme_key_add_sig (gpgme_key_t key, char *src)
Packit d7e8d0
{
Packit d7e8d0
  int src_len = src ? strlen (src) : 0;
Packit d7e8d0
  gpgme_user_id_t uid;
Packit d7e8d0
  gpgme_key_sig_t sig;
Packit d7e8d0
Packit d7e8d0
  assert (key);	/* XXX */
Packit d7e8d0
Packit d7e8d0
  uid = key->_last_uid;
Packit d7e8d0
  assert (uid);	/* XXX */
Packit d7e8d0
Packit d7e8d0
  /* We can malloc a buffer of the same length, because the converted
Packit d7e8d0
     string will never be larger.  Actually we allocate it twice the
Packit d7e8d0
     size, so that we are able to store the parsed stuff there too.  */
Packit d7e8d0
  sig = malloc (sizeof (*sig) + 2 * src_len + 3);
Packit d7e8d0
  if (!sig)
Packit d7e8d0
    return NULL;
Packit d7e8d0
  memset (sig, 0, sizeof *sig);
Packit d7e8d0
Packit d7e8d0
  sig->keyid = sig->_keyid;
Packit d7e8d0
  sig->_keyid[16] = '\0';
Packit d7e8d0
  sig->uid = ((char *) sig) + sizeof (*sig);
Packit d7e8d0
Packit d7e8d0
  if (src)
Packit d7e8d0
    {
Packit d7e8d0
      char *dst = sig->uid;
Packit d7e8d0
      _gpgme_decode_c_string (src, &dst, src_len + 1);
Packit d7e8d0
      dst += strlen (dst) + 1;
Packit d7e8d0
      if (key->protocol == GPGME_PROTOCOL_CMS)
Packit d7e8d0
	parse_x509_user_id (sig->uid, &sig->name, &sig->email,
Packit d7e8d0
			    &sig->comment, dst);
Packit d7e8d0
      else
Packit d7e8d0
	parse_user_id (sig->uid, &sig->name, &sig->email,
Packit d7e8d0
		       &sig->comment, dst);
Packit d7e8d0
    }
Packit d7e8d0
  else
Packit d7e8d0
    sig->uid[0] = '\0';
Packit d7e8d0
Packit d7e8d0
  if (!uid->signatures)
Packit d7e8d0
    uid->signatures = sig;
Packit d7e8d0
  if (uid->_last_keysig)
Packit d7e8d0
    uid->_last_keysig->next = sig;
Packit d7e8d0
  uid->_last_keysig = sig;
Packit d7e8d0
Packit d7e8d0
  return sig;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0

Packit d7e8d0
/* Acquire a reference to KEY.  */
Packit d7e8d0
void
Packit d7e8d0
gpgme_key_ref (gpgme_key_t key)
Packit d7e8d0
{
Packit d7e8d0
  LOCK (key_ref_lock);
Packit d7e8d0
  key->_refs++;
Packit d7e8d0
  UNLOCK (key_ref_lock);
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
/* gpgme_key_unref releases the key object.  Note, that this function
Packit d7e8d0
   may not do an actual release if there are other shallow copies of
Packit d7e8d0
   the objects.  You have to call this function for every newly
Packit d7e8d0
   created key object as well as for every gpgme_key_ref() done on the
Packit d7e8d0
   key object.  */
Packit d7e8d0
void
Packit d7e8d0
gpgme_key_unref (gpgme_key_t key)
Packit d7e8d0
{
Packit d7e8d0
  gpgme_user_id_t uid;
Packit d7e8d0
  gpgme_subkey_t subkey;
Packit d7e8d0
Packit d7e8d0
  if (!key)
Packit d7e8d0
    return;
Packit d7e8d0
Packit d7e8d0
  LOCK (key_ref_lock);
Packit d7e8d0
  assert (key->_refs > 0);
Packit d7e8d0
  if (--key->_refs)
Packit d7e8d0
    {
Packit d7e8d0
      UNLOCK (key_ref_lock);
Packit d7e8d0
      return;
Packit d7e8d0
    }
Packit d7e8d0
  UNLOCK (key_ref_lock);
Packit d7e8d0
Packit d7e8d0
  subkey = key->subkeys;
Packit d7e8d0
  while (subkey)
Packit d7e8d0
    {
Packit d7e8d0
      gpgme_subkey_t next = subkey->next;
Packit d7e8d0
      free (subkey->fpr);
Packit d7e8d0
      free (subkey->curve);
Packit d7e8d0
      free (subkey->keygrip);
Packit d7e8d0
      free (subkey->card_number);
Packit d7e8d0
      free (subkey);
Packit d7e8d0
      subkey = next;
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  uid = key->uids;
Packit d7e8d0
  while (uid)
Packit d7e8d0
    {
Packit d7e8d0
      gpgme_user_id_t next_uid = uid->next;
Packit d7e8d0
      gpgme_key_sig_t keysig = uid->signatures;
Packit d7e8d0
      gpgme_tofu_info_t tofu = uid->tofu;
Packit d7e8d0
Packit d7e8d0
      while (keysig)
Packit d7e8d0
	{
Packit d7e8d0
	  gpgme_key_sig_t next_keysig = keysig->next;
Packit d7e8d0
	  gpgme_sig_notation_t notation = keysig->notations;
Packit d7e8d0
Packit d7e8d0
	  while (notation)
Packit d7e8d0
	    {
Packit d7e8d0
	      gpgme_sig_notation_t next_notation = notation->next;
Packit d7e8d0
Packit d7e8d0
	      _gpgme_sig_notation_free (notation);
Packit d7e8d0
	      notation = next_notation;
Packit d7e8d0
	    }
Packit d7e8d0
Packit d7e8d0
          free (keysig);
Packit d7e8d0
	  keysig = next_keysig;
Packit d7e8d0
        }
Packit d7e8d0
Packit d7e8d0
      while (tofu)
Packit d7e8d0
        {
Packit d7e8d0
          /* NB: The ->next is currently not used but we are prepared
Packit d7e8d0
           * for it.  */
Packit d7e8d0
          gpgme_tofu_info_t tofu_next = tofu->next;
Packit d7e8d0
Packit d7e8d0
          free (tofu->description);
Packit d7e8d0
          free (tofu);
Packit d7e8d0
          tofu = tofu_next;
Packit d7e8d0
        }
Packit d7e8d0
Packit d7e8d0
      free (uid->address);
Packit d7e8d0
      free (uid);
Packit d7e8d0
      uid = next_uid;
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  free (key->issuer_serial);
Packit d7e8d0
  free (key->issuer_name);
Packit d7e8d0
  free (key->chain_id);
Packit d7e8d0
  free (key->fpr);
Packit d7e8d0
Packit d7e8d0
  free (key);
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0

Packit d7e8d0
/* Support functions.  */
Packit d7e8d0
Packit d7e8d0
/* Create a dummy key to specify an email address.  */
Packit d7e8d0
gpgme_error_t
Packit d7e8d0
gpgme_key_from_uid (gpgme_key_t *r_key, const char *name)
Packit d7e8d0
{
Packit d7e8d0
  gpgme_error_t err;
Packit d7e8d0
  gpgme_key_t key;
Packit d7e8d0
Packit d7e8d0
  *r_key = NULL;
Packit d7e8d0
  err = _gpgme_key_new (&key);
Packit d7e8d0
  if (err)
Packit d7e8d0
    return err;
Packit d7e8d0
Packit d7e8d0
  /* Note: protocol doesn't matter if only email is provided.  */
Packit d7e8d0
  err = _gpgme_key_append_name (key, name, 0);
Packit d7e8d0
  if (err)
Packit d7e8d0
    gpgme_key_unref (key);
Packit d7e8d0
  else
Packit d7e8d0
    *r_key = key;
Packit d7e8d0
Packit d7e8d0
  return err;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0

Packit d7e8d0
/* Compatibility interfaces.  */
Packit d7e8d0
Packit d7e8d0
void
Packit d7e8d0
gpgme_key_release (gpgme_key_t key)
Packit d7e8d0
{
Packit d7e8d0
  gpgme_key_unref (key);
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
static const char *
Packit d7e8d0
otrust_to_string (int otrust)
Packit d7e8d0
{
Packit d7e8d0
  switch (otrust)
Packit d7e8d0
    {
Packit d7e8d0
    case GPGME_VALIDITY_NEVER:
Packit d7e8d0
      return "n";
Packit d7e8d0
Packit d7e8d0
    case GPGME_VALIDITY_MARGINAL:
Packit d7e8d0
      return "m";
Packit d7e8d0
Packit d7e8d0
    case GPGME_VALIDITY_FULL:
Packit d7e8d0
      return "f";
Packit d7e8d0
Packit d7e8d0
    case GPGME_VALIDITY_ULTIMATE:
Packit d7e8d0
      return "u";
Packit d7e8d0
Packit d7e8d0
    default:
Packit d7e8d0
      return "?";
Packit d7e8d0
    }
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
static const char *
Packit d7e8d0
validity_to_string (int validity)
Packit d7e8d0
{
Packit d7e8d0
  switch (validity)
Packit d7e8d0
    {
Packit d7e8d0
    case GPGME_VALIDITY_UNDEFINED:
Packit d7e8d0
      return "q";
Packit d7e8d0
Packit d7e8d0
    case GPGME_VALIDITY_NEVER:
Packit d7e8d0
      return "n";
Packit d7e8d0
Packit d7e8d0
    case GPGME_VALIDITY_MARGINAL:
Packit d7e8d0
      return "m";
Packit d7e8d0
Packit d7e8d0
    case GPGME_VALIDITY_FULL:
Packit d7e8d0
      return "f";
Packit d7e8d0
Packit d7e8d0
    case GPGME_VALIDITY_ULTIMATE:
Packit d7e8d0
      return "u";
Packit d7e8d0
Packit d7e8d0
    case GPGME_VALIDITY_UNKNOWN:
Packit d7e8d0
    default:
Packit d7e8d0
      return "?";
Packit d7e8d0
    }
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
static const char *
Packit d7e8d0
capabilities_to_string (gpgme_subkey_t subkey)
Packit d7e8d0
{
Packit d7e8d0
  static const char *const strings[8] =
Packit d7e8d0
    {
Packit d7e8d0
      "",
Packit d7e8d0
      "c",
Packit d7e8d0
      "s",
Packit d7e8d0
      "sc",
Packit d7e8d0
      "e",
Packit d7e8d0
      "ec",
Packit d7e8d0
      "es",
Packit d7e8d0
      "esc"
Packit d7e8d0
    };
Packit d7e8d0
  return strings[(!!subkey->can_encrypt << 2)
Packit d7e8d0
		 | (!!subkey->can_sign << 1)
Packit d7e8d0
		 | (!!subkey->can_certify)];
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
/* Return the value of the attribute WHAT of ITEM, which has to be
Packit d7e8d0
   representable by a string.  */
Packit d7e8d0
const char *
Packit d7e8d0
gpgme_key_get_string_attr (gpgme_key_t key, _gpgme_attr_t what,
Packit d7e8d0
			   const void *reserved, int idx)
Packit d7e8d0
{
Packit d7e8d0
  gpgme_subkey_t subkey;
Packit d7e8d0
  gpgme_user_id_t uid;
Packit d7e8d0
  int i;
Packit d7e8d0
Packit d7e8d0
  if (!key || reserved || idx < 0)
Packit d7e8d0
    return NULL;
Packit d7e8d0
Packit d7e8d0
  /* Select IDXth subkey.  */
Packit d7e8d0
  subkey = key->subkeys;
Packit d7e8d0
  for (i = 0; i < idx; i++)
Packit d7e8d0
    {
Packit d7e8d0
      subkey = subkey->next;
Packit d7e8d0
      if (!subkey)
Packit d7e8d0
	break;
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  /* Select the IDXth user ID.  */
Packit d7e8d0
  uid = key->uids;
Packit d7e8d0
  for (i = 0; i < idx; i++)
Packit d7e8d0
    {
Packit d7e8d0
      uid = uid->next;
Packit d7e8d0
      if (!uid)
Packit d7e8d0
	break;
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  switch (what)
Packit d7e8d0
    {
Packit d7e8d0
    case GPGME_ATTR_KEYID:
Packit d7e8d0
      return subkey ? subkey->keyid : NULL;
Packit d7e8d0
Packit d7e8d0
    case GPGME_ATTR_FPR:
Packit d7e8d0
      return subkey ? subkey->fpr : NULL;
Packit d7e8d0
Packit d7e8d0
    case GPGME_ATTR_ALGO:
Packit d7e8d0
      return subkey ? gpgme_pubkey_algo_name (subkey->pubkey_algo) : NULL;
Packit d7e8d0
Packit d7e8d0
    case GPGME_ATTR_TYPE:
Packit d7e8d0
      return key->protocol == GPGME_PROTOCOL_CMS ? "X.509" : "PGP";
Packit d7e8d0
Packit d7e8d0
    case GPGME_ATTR_OTRUST:
Packit d7e8d0
      return otrust_to_string (key->owner_trust);
Packit d7e8d0
Packit d7e8d0
    case GPGME_ATTR_USERID:
Packit d7e8d0
      return uid ? uid->uid : NULL;
Packit d7e8d0
Packit d7e8d0
    case GPGME_ATTR_NAME:
Packit d7e8d0
      return uid ? uid->name : NULL;
Packit d7e8d0
Packit d7e8d0
    case GPGME_ATTR_EMAIL:
Packit d7e8d0
      return uid ? uid->email : NULL;
Packit d7e8d0
Packit d7e8d0
    case GPGME_ATTR_COMMENT:
Packit d7e8d0
      return uid ? uid->comment : NULL;
Packit d7e8d0
Packit d7e8d0
    case GPGME_ATTR_VALIDITY:
Packit d7e8d0
      return uid ? validity_to_string (uid->validity) : NULL;
Packit d7e8d0
Packit d7e8d0
    case GPGME_ATTR_KEY_CAPS:
Packit d7e8d0
      return subkey ? capabilities_to_string (subkey) : NULL;
Packit d7e8d0
Packit d7e8d0
    case GPGME_ATTR_SERIAL:
Packit d7e8d0
      return key->issuer_serial;
Packit d7e8d0
Packit d7e8d0
    case GPGME_ATTR_ISSUER:
Packit d7e8d0
      return idx ? NULL : key->issuer_name;
Packit d7e8d0
Packit d7e8d0
    case GPGME_ATTR_CHAINID:
Packit d7e8d0
      return key->chain_id;
Packit d7e8d0
Packit d7e8d0
    default:
Packit d7e8d0
      return NULL;
Packit d7e8d0
    }
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
unsigned long
Packit d7e8d0
gpgme_key_get_ulong_attr (gpgme_key_t key, _gpgme_attr_t what,
Packit d7e8d0
			  const void *reserved, int idx)
Packit d7e8d0
{
Packit d7e8d0
  gpgme_subkey_t subkey;
Packit d7e8d0
  gpgme_user_id_t uid;
Packit d7e8d0
  int i;
Packit d7e8d0
Packit d7e8d0
  if (!key || reserved || idx < 0)
Packit d7e8d0
    return 0;
Packit d7e8d0
Packit d7e8d0
  /* Select IDXth subkey.  */
Packit d7e8d0
  subkey = key->subkeys;
Packit d7e8d0
  for (i = 0; i < idx; i++)
Packit d7e8d0
    {
Packit d7e8d0
      subkey = subkey->next;
Packit d7e8d0
      if (!subkey)
Packit d7e8d0
	break;
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  /* Select the IDXth user ID.  */
Packit d7e8d0
  uid = key->uids;
Packit d7e8d0
  for (i = 0; i < idx; i++)
Packit d7e8d0
    {
Packit d7e8d0
      uid = uid->next;
Packit d7e8d0
      if (!uid)
Packit d7e8d0
	break;
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  switch (what)
Packit d7e8d0
    {
Packit d7e8d0
    case GPGME_ATTR_ALGO:
Packit d7e8d0
      return subkey ? (unsigned long) subkey->pubkey_algo : 0;
Packit d7e8d0
Packit d7e8d0
    case GPGME_ATTR_LEN:
Packit d7e8d0
      return subkey ? (unsigned long) subkey->length : 0;
Packit d7e8d0
Packit d7e8d0
    case GPGME_ATTR_TYPE:
Packit d7e8d0
      return key->protocol == GPGME_PROTOCOL_CMS ? 1 : 0;
Packit d7e8d0
Packit d7e8d0
    case GPGME_ATTR_CREATED:
Packit d7e8d0
      return (subkey && subkey->timestamp >= 0)
Packit d7e8d0
	? (unsigned long) subkey->timestamp : 0;
Packit d7e8d0
Packit d7e8d0
    case GPGME_ATTR_EXPIRE:
Packit d7e8d0
      return (subkey && subkey->expires >= 0)
Packit d7e8d0
	? (unsigned long) subkey->expires : 0;
Packit d7e8d0
Packit d7e8d0
    case GPGME_ATTR_VALIDITY:
Packit d7e8d0
      return uid ? uid->validity : 0;
Packit d7e8d0
Packit d7e8d0
    case GPGME_ATTR_OTRUST:
Packit d7e8d0
      return key->owner_trust;
Packit d7e8d0
Packit d7e8d0
    case GPGME_ATTR_IS_SECRET:
Packit d7e8d0
      return !!key->secret;
Packit d7e8d0
Packit d7e8d0
    case GPGME_ATTR_KEY_REVOKED:
Packit d7e8d0
      return subkey ? subkey->revoked : 0;
Packit d7e8d0
Packit d7e8d0
    case GPGME_ATTR_KEY_INVALID:
Packit d7e8d0
      return subkey ? subkey->invalid : 0;
Packit d7e8d0
Packit d7e8d0
    case GPGME_ATTR_KEY_EXPIRED:
Packit d7e8d0
      return subkey ? subkey->expired : 0;
Packit d7e8d0
Packit d7e8d0
    case GPGME_ATTR_KEY_DISABLED:
Packit d7e8d0
      return subkey ? subkey->disabled : 0;
Packit d7e8d0
Packit d7e8d0
    case GPGME_ATTR_UID_REVOKED:
Packit d7e8d0
      return uid ? uid->revoked : 0;
Packit d7e8d0
Packit d7e8d0
    case GPGME_ATTR_UID_INVALID:
Packit d7e8d0
      return uid ? uid->invalid : 0;
Packit d7e8d0
Packit d7e8d0
    case GPGME_ATTR_CAN_ENCRYPT:
Packit d7e8d0
      return key->can_encrypt;
Packit d7e8d0
Packit d7e8d0
    case GPGME_ATTR_CAN_SIGN:
Packit d7e8d0
      return key->can_sign;
Packit d7e8d0
Packit d7e8d0
    case GPGME_ATTR_CAN_CERTIFY:
Packit d7e8d0
      return key->can_certify;
Packit d7e8d0
Packit d7e8d0
    default:
Packit d7e8d0
      return 0;
Packit d7e8d0
    }
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
static gpgme_key_sig_t
Packit d7e8d0
get_keysig (gpgme_key_t key, int uid_idx, int idx)
Packit d7e8d0
{
Packit d7e8d0
  gpgme_user_id_t uid;
Packit d7e8d0
  gpgme_key_sig_t sig;
Packit d7e8d0
Packit d7e8d0
  if (!key || uid_idx < 0 || idx < 0)
Packit d7e8d0
    return NULL;
Packit d7e8d0
Packit d7e8d0
  uid = key->uids;
Packit d7e8d0
  while (uid && uid_idx > 0)
Packit d7e8d0
    {
Packit d7e8d0
      uid = uid->next;
Packit d7e8d0
      uid_idx--;
Packit d7e8d0
    }
Packit d7e8d0
  if (!uid)
Packit d7e8d0
    return NULL;
Packit d7e8d0
Packit d7e8d0
  sig = uid->signatures;
Packit d7e8d0
  while (sig && idx > 0)
Packit d7e8d0
    {
Packit d7e8d0
      sig = sig->next;
Packit d7e8d0
      idx--;
Packit d7e8d0
    }
Packit d7e8d0
  return sig;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
const char *
Packit d7e8d0
gpgme_key_sig_get_string_attr (gpgme_key_t key, int uid_idx,
Packit d7e8d0
			       _gpgme_attr_t what,
Packit d7e8d0
			       const void *reserved, int idx)
Packit d7e8d0
{
Packit d7e8d0
  gpgme_key_sig_t certsig = get_keysig (key, uid_idx, idx);
Packit d7e8d0
Packit d7e8d0
  if (!certsig || reserved)
Packit d7e8d0
    return NULL;
Packit d7e8d0
Packit d7e8d0
  switch (what)
Packit d7e8d0
    {
Packit d7e8d0
    case GPGME_ATTR_KEYID:
Packit d7e8d0
      return certsig->keyid;
Packit d7e8d0
Packit d7e8d0
    case GPGME_ATTR_ALGO:
Packit d7e8d0
      return gpgme_pubkey_algo_name (certsig->pubkey_algo);
Packit d7e8d0
Packit d7e8d0
    case GPGME_ATTR_USERID:
Packit d7e8d0
      return certsig->uid;
Packit d7e8d0
Packit d7e8d0
    case GPGME_ATTR_NAME:
Packit d7e8d0
      return certsig->name;
Packit d7e8d0
Packit d7e8d0
    case GPGME_ATTR_EMAIL:
Packit d7e8d0
      return certsig->email;
Packit d7e8d0
Packit d7e8d0
    case GPGME_ATTR_COMMENT:
Packit d7e8d0
      return certsig->comment;
Packit d7e8d0
Packit d7e8d0
    default:
Packit d7e8d0
      return NULL;
Packit d7e8d0
    }
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
unsigned long
Packit d7e8d0
gpgme_key_sig_get_ulong_attr (gpgme_key_t key, int uid_idx, _gpgme_attr_t what,
Packit d7e8d0
			      const void *reserved, int idx)
Packit d7e8d0
{
Packit d7e8d0
  gpgme_key_sig_t certsig = get_keysig (key, uid_idx, idx);
Packit d7e8d0
Packit d7e8d0
  if (!certsig || reserved)
Packit d7e8d0
    return 0;
Packit d7e8d0
Packit d7e8d0
  switch (what)
Packit d7e8d0
    {
Packit d7e8d0
    case GPGME_ATTR_ALGO:
Packit d7e8d0
      return (unsigned long) certsig->pubkey_algo;
Packit d7e8d0
Packit d7e8d0
    case GPGME_ATTR_CREATED:
Packit d7e8d0
      return certsig->timestamp < 0 ? 0L : (unsigned long) certsig->timestamp;
Packit d7e8d0
Packit d7e8d0
    case GPGME_ATTR_EXPIRE:
Packit d7e8d0
      return certsig->expires < 0 ? 0L : (unsigned long) certsig->expires;
Packit d7e8d0
Packit d7e8d0
    case GPGME_ATTR_KEY_REVOKED:
Packit d7e8d0
      return certsig->revoked;
Packit d7e8d0
Packit d7e8d0
    case GPGME_ATTR_KEY_INVALID:
Packit d7e8d0
      return certsig->invalid;
Packit d7e8d0
Packit d7e8d0
    case GPGME_ATTR_KEY_EXPIRED:
Packit d7e8d0
      return certsig->expired;
Packit d7e8d0
Packit d7e8d0
    case GPGME_ATTR_SIG_CLASS:
Packit d7e8d0
      return certsig->sig_class;
Packit d7e8d0
Packit d7e8d0
    case GPGME_ATTR_SIG_STATUS:
Packit d7e8d0
      return certsig->status;
Packit d7e8d0
Packit d7e8d0
    default:
Packit d7e8d0
      return 0;
Packit d7e8d0
    }
Packit d7e8d0
}