diff options
| author | Marcus Brinkmann <[email protected]> | 2008-11-03 17:24:09 +0000 | 
|---|---|---|
| committer | Marcus Brinkmann <[email protected]> | 2008-11-03 17:24:09 +0000 | 
| commit | 66d0fa1973e5e1a1bff619de8b595673d1b76cc5 (patch) | |
| tree | 4b1f8e470fa455cbe3d9b5c4ab6fb4fa77f20ba3 /src/key.c | |
| parent | assuan/ (diff) | |
| download | gpgme-66d0fa1973e5e1a1bff619de8b595673d1b76cc5.tar.gz gpgme-66d0fa1973e5e1a1bff619de8b595673d1b76cc5.zip | |
008-11-03  Marcus Brinkmann  <[email protected]>
        * configure.ac: Replace gpgme paths with src.
        * gpgme: Move to ...
        * src: ... this new directory.
assuan/
2008-11-03  Marcus Brinkmann  <[email protected]>
	* Makefile.am (INCLUDES): Replace gpgme path with src.
tests/
2008-11-03  Marcus Brinkmann  <[email protected]>
        * gpgsm/Makefile.am (INCLUDES, LDADD): Replace gpgme path with src.
        * gpg/Makefile.am (INCLUDES, LDADD, t_thread1_LDADD): Likewise.
	* Makefile.am (LDADD): Likewise.
Diffstat (limited to 'src/key.c')
| -rw-r--r-- | src/key.c | 724 | 
1 files changed, 724 insertions, 0 deletions
| diff --git a/src/key.c b/src/key.c new file mode 100644 index 00000000..c9f48f87 --- /dev/null +++ b/src/key.c @@ -0,0 +1,724 @@ +/* key.c - Key objects. +   Copyright (C) 2000 Werner Koch (dd9jn) +   Copyright (C) 2001, 2002, 2003, 2004 g10 Code GmbH + +   This file is part of GPGME. +  +   GPGME is free software; you can redistribute it and/or modify it +   under the terms of the GNU Lesser General Public License as +   published by the Free Software Foundation; either version 2.1 of +   the License, or (at your option) any later version. +    +   GPGME is distributed in the hope that it will be useful, but +   WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. +    +   You should have received a copy of the GNU Lesser General Public +   License along with this program; if not, write to the Free Software +   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +   02111-1307, USA.  */ + +#if HAVE_CONFIG_H +#include <config.h> +#endif +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <errno.h> + +#include "util.h" +#include "ops.h" +#include "sema.h" + + +/* Protects all reference counters in keys.  All other accesses to a +   key are read only.  */ +DEFINE_STATIC_LOCK (key_ref_lock); + + +/* Create a new key.  */ +gpgme_error_t +_gpgme_key_new (gpgme_key_t *r_key) +{ +  gpgme_key_t key; + +  key = calloc (1, sizeof *key); +  if (!key) +    return gpg_error_from_errno (errno); +  key->_refs = 1; + +  *r_key = key; +  return 0; +} + + +gpgme_error_t +_gpgme_key_add_subkey (gpgme_key_t key, gpgme_subkey_t *r_subkey) +{ +  gpgme_subkey_t subkey; + +  subkey = calloc (1, sizeof *subkey); +  if (!subkey) +    return gpg_error_from_errno (errno); +  subkey->keyid = subkey->_keyid; +  subkey->_keyid[16] = '\0'; + +  if (!key->subkeys) +    key->subkeys = subkey; +  if (key->_last_subkey) +    key->_last_subkey->next = subkey; +  key->_last_subkey = subkey; + +  *r_subkey = subkey; +  return 0; +} + + +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 (char *src, char **name, char **email, +	       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 (char *src, char **name, char **email, +		    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; +} + + +/* Take a name from the --with-colon listing, remove certain escape +   sequences sequences and put it into the list of UIDs.  */ +gpgme_error_t +_gpgme_key_append_name (gpgme_key_t key, char *src) +{ +  gpgme_user_id_t uid; +  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 * src_len + 3); +  if (!uid) +    return gpg_error_from_errno (errno); +  memset (uid, 0, sizeof *uid); + +  uid->uid = ((char *) uid) + sizeof (*uid); +  dst = uid->uid; +  _gpgme_decode_c_string (src, &dst, src_len + 1); + +  dst += strlen (dst) + 1; +  if (key->protocol == GPGME_PROTOCOL_CMS) +    parse_x509_user_id (uid->uid, &uid->name, &uid->email, +			&uid->comment, dst); +  else +    parse_user_id (uid->uid, &uid->name, &uid->email, +		   &uid->comment, dst); + +  if (!key->uids) +    key->uids = uid; +  if (key->_last_uid) +    key->_last_uid->next = uid; +  key->_last_uid = uid; + +  return 0; +} + + +gpgme_key_sig_t +_gpgme_key_add_sig (gpgme_key_t key, char *src) +{ +  int src_len = src ? strlen (src) : 0; +  gpgme_user_id_t uid; +  gpgme_key_sig_t sig; + +  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.  */ +  sig = malloc (sizeof (*sig) + 2 * src_len + 3); +  if (!sig) +    return NULL; +  memset (sig, 0, sizeof *sig); + +  sig->keyid = sig->_keyid; +  sig->_keyid[16] = '\0'; +  sig->uid = ((char *) sig) + sizeof (*sig); + +  if (src) +    { +      char *dst = sig->uid; +      _gpgme_decode_c_string (src, &dst, src_len + 1); +      dst += strlen (dst) + 1; +      if (key->protocol == GPGME_PROTOCOL_CMS) +	parse_x509_user_id (sig->uid, &sig->name, &sig->email, +			    &sig->comment, dst); +      else +	parse_user_id (sig->uid, &sig->name, &sig->email, +		       &sig->comment, dst); +    } +  else +    sig->uid = '\0'; + +  if (!uid->signatures) +    uid->signatures = sig; +  if (uid->_last_keysig) +    uid->_last_keysig->next = sig; +  uid->_last_keysig = sig; + +  return sig; +} + + +/* Acquire a reference to KEY.  */ +void +gpgme_key_ref (gpgme_key_t key) +{ +  LOCK (key_ref_lock); +  key->_refs++; +  UNLOCK (key_ref_lock); +} + + +/* gpgme_key_unref releases the key object.  Note, that this function +   may not do an actual release if there are other shallow copies of +   the objects.  You have to call this function for every newly +   created key object as well as for every gpgme_key_ref() done on the +   key object.  */ +void +gpgme_key_unref (gpgme_key_t key) +{ +  gpgme_user_id_t uid; +  gpgme_subkey_t subkey; + +  if (!key) +    return; + +  LOCK (key_ref_lock); +  assert (key->_refs > 0); +  if (--key->_refs) +    { +      UNLOCK (key_ref_lock); +      return; +    } +  UNLOCK (key_ref_lock); + +  subkey = key->subkeys; +  while (subkey) +    { +      gpgme_subkey_t next = subkey->next; +      if (subkey->fpr) +	free (subkey->fpr); +      free (subkey); +      subkey = next; +    } + +  uid = key->uids; +  while (uid) +    { +      gpgme_user_id_t next_uid = uid->next; +      gpgme_key_sig_t keysig = uid->signatures; + +      while (keysig) +	{ +	  gpgme_key_sig_t next_keysig = keysig->next; +	  gpgme_sig_notation_t notation = keysig->notations; + +	  while (notation) +	    { +	      gpgme_sig_notation_t next_notation = notation->next; + +	      _gpgme_sig_notation_free (notation); +	      notation = next_notation; +	    } + +          free (keysig); +	  keysig = next_keysig; +        } +      free (uid); +      uid = next_uid; +    } +   +  if (key->issuer_serial) +    free (key->issuer_serial); +  if (key->issuer_name) +    free (key->issuer_name); + +  if (key->chain_id) +    free (key->chain_id); + +  free (key); +} + + +/* Compatibility interfaces.  */ + +void +gpgme_key_release (gpgme_key_t key) +{ +  gpgme_key_unref (key); +} + + +static const char * +otrust_to_string (int otrust) +{ +  switch (otrust) +    { +    case GPGME_VALIDITY_NEVER: +      return "n"; + +    case GPGME_VALIDITY_MARGINAL: +      return "m"; + +    case GPGME_VALIDITY_FULL: +      return "f"; + +    case GPGME_VALIDITY_ULTIMATE: +      return "u"; + +    default: +      return "?"; +    } +} + + +static const char * +validity_to_string (int validity) +{ +  switch (validity) +    { +    case GPGME_VALIDITY_UNDEFINED: +      return "q"; + +    case GPGME_VALIDITY_NEVER: +      return "n"; + +    case GPGME_VALIDITY_MARGINAL: +      return "m"; + +    case GPGME_VALIDITY_FULL: +      return "f"; + +    case GPGME_VALIDITY_ULTIMATE: +      return "u"; + +    case GPGME_VALIDITY_UNKNOWN: +    default: +      return "?"; +    } +} + + +static const char * +capabilities_to_string (gpgme_subkey_t subkey) +{ +  static const char *const strings[8] = +    { +      "", +      "c", +      "s", +      "sc", +      "e", +      "ec", +      "es", +      "esc" +    }; +  return strings[(!!subkey->can_encrypt << 2) +		 | (!!subkey->can_sign << 1) +		 | (!!subkey->can_certify)]; +} + + +/* Return the value of the attribute WHAT of ITEM, which has to be +   representable by a string.  */ +const char * +gpgme_key_get_string_attr (gpgme_key_t key, _gpgme_attr_t what, +			   const void *reserved, int idx) +{ +  gpgme_subkey_t subkey; +  gpgme_user_id_t uid; +  int i; + +  if (!key || reserved || idx < 0) +    return NULL; + +  /* Select IDXth subkey.  */ +  subkey = key->subkeys; +  for (i = 0; i < idx; i++) +    { +      subkey = subkey->next; +      if (!subkey) +	break; +    } + +  /* Select the IDXth user ID.  */ +  uid = key->uids; +  for (i = 0; i < idx; i++) +    { +      uid = uid->next; +      if (!uid) +	break; +    } + +  switch (what) +    { +    case GPGME_ATTR_KEYID: +      return subkey ? subkey->keyid : NULL; + +    case GPGME_ATTR_FPR: +      return subkey ? subkey->fpr : NULL; + +    case GPGME_ATTR_ALGO:     +      return subkey ? gpgme_pubkey_algo_name (subkey->pubkey_algo) : NULL; + +    case GPGME_ATTR_TYPE: +      return key->protocol == GPGME_PROTOCOL_CMS ? "X.509" : "PGP"; + +    case GPGME_ATTR_OTRUST: +      return otrust_to_string (key->owner_trust); + +    case GPGME_ATTR_USERID:   +      return uid ? uid->uid : NULL; + +    case GPGME_ATTR_NAME:    +      return uid ? uid->name : NULL; + +    case GPGME_ATTR_EMAIL: +      return uid ? uid->email : NULL; + +    case GPGME_ATTR_COMMENT: +      return uid ? uid->comment : NULL; + +    case GPGME_ATTR_VALIDITY: +      return uid ? validity_to_string (uid->validity) : NULL; + +    case GPGME_ATTR_KEY_CAPS:     +      return subkey ? capabilities_to_string (subkey) : NULL; + +    case GPGME_ATTR_SERIAL: +      return key->issuer_serial; + +    case GPGME_ATTR_ISSUER: +      return idx ? NULL : key->issuer_name; + +    case GPGME_ATTR_CHAINID: +      return key->chain_id; + +    default: +      return NULL; +    } +} + + +unsigned long +gpgme_key_get_ulong_attr (gpgme_key_t key, _gpgme_attr_t what, +			  const void *reserved, int idx) +{ +  gpgme_subkey_t subkey; +  gpgme_user_id_t uid; +  int i; + +  if (!key || reserved || idx < 0) +    return 0; + +  /* Select IDXth subkey.  */ +  subkey = key->subkeys; +  for (i = 0; i < idx; i++) +    { +      subkey = subkey->next; +      if (!subkey) +	break; +    } + +  /* Select the IDXth user ID.  */ +  uid = key->uids; +  for (i = 0; i < idx; i++) +    { +      uid = uid->next; +      if (!uid) +	break; +    } + +  switch (what) +    { +    case GPGME_ATTR_ALGO: +      return subkey ? (unsigned long) subkey->pubkey_algo : 0; + +    case GPGME_ATTR_LEN: +      return subkey ? (unsigned long) subkey->length : 0; + +    case GPGME_ATTR_TYPE: +      return key->protocol == GPGME_PROTOCOL_CMS ? 1 : 0; + +    case GPGME_ATTR_CREATED: +      return (subkey && subkey->timestamp >= 0) +	? (unsigned long) subkey->timestamp : 0; + +    case GPGME_ATTR_EXPIRE:  +      return (subkey && subkey->expires >= 0) +	? (unsigned long) subkey->expires : 0; + +    case GPGME_ATTR_VALIDITY: +      return uid ? uid->validity : 0; + +    case GPGME_ATTR_OTRUST: +      return key->owner_trust; + +    case GPGME_ATTR_IS_SECRET: +      return !!key->secret; + +    case GPGME_ATTR_KEY_REVOKED: +      return subkey ? subkey->revoked : 0; + +    case GPGME_ATTR_KEY_INVALID: +      return subkey ? subkey->invalid : 0; + +    case GPGME_ATTR_KEY_EXPIRED: +      return subkey ? subkey->expired : 0; + +    case GPGME_ATTR_KEY_DISABLED: +      return subkey ? subkey->disabled : 0; + +    case GPGME_ATTR_UID_REVOKED: +      return uid ? uid->revoked : 0; + +    case GPGME_ATTR_UID_INVALID: +      return uid ? uid->invalid : 0; + +    case GPGME_ATTR_CAN_ENCRYPT: +      return key->can_encrypt; + +    case GPGME_ATTR_CAN_SIGN: +      return key->can_sign; + +    case GPGME_ATTR_CAN_CERTIFY: +      return key->can_certify; + +    default: +      return 0; +    } +} + + +static gpgme_key_sig_t +get_keysig (gpgme_key_t key, int uid_idx, int idx) +{ +  gpgme_user_id_t uid; +  gpgme_key_sig_t sig; + +  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; + +  sig = uid->signatures; +  while (sig && idx > 0) +    { +      sig = sig->next; +      idx--; +    } +  return sig; +} + + +const char * +gpgme_key_sig_get_string_attr (gpgme_key_t key, int uid_idx, +			       _gpgme_attr_t what, +			       const void *reserved, int idx) +{ +  gpgme_key_sig_t certsig = get_keysig (key, uid_idx, idx); + +  if (!certsig || reserved) +    return NULL; + +  switch (what) +    { +    case GPGME_ATTR_KEYID: +      return certsig->keyid; + +    case GPGME_ATTR_ALGO:     +      return gpgme_pubkey_algo_name (certsig->pubkey_algo); + +    case GPGME_ATTR_USERID: +      return certsig->uid; + +    case GPGME_ATTR_NAME:    +      return certsig->name; + +    case GPGME_ATTR_EMAIL: +      return certsig->email; + +    case GPGME_ATTR_COMMENT: +      return certsig->comment; +    +    default: +      return NULL; +    } +} + + +unsigned long +gpgme_key_sig_get_ulong_attr (gpgme_key_t key, int uid_idx, _gpgme_attr_t what, +			      const void *reserved, int idx) +{ +  gpgme_key_sig_t certsig = get_keysig (key, uid_idx, idx); + +  if (!certsig || reserved) +    return 0; + +  switch (what) +    { +    case GPGME_ATTR_ALGO:     +      return (unsigned long) certsig->pubkey_algo; + +    case GPGME_ATTR_CREATED:  +      return certsig->timestamp < 0 ? 0L : (unsigned long) certsig->timestamp; + +    case GPGME_ATTR_EXPIRE:  +      return certsig->expires < 0 ? 0L : (unsigned long) certsig->expires; + +    case GPGME_ATTR_KEY_REVOKED: +      return certsig->revoked; + +    case GPGME_ATTR_KEY_INVALID: +      return certsig->invalid; + +    case GPGME_ATTR_KEY_EXPIRED: +      return certsig->expired; + +    case GPGME_ATTR_SIG_CLASS: +      return certsig->sig_class; + +    case GPGME_ATTR_SIG_STATUS: +      return certsig->status; + +    default: +      return 0; +    } +} | 
