diff --git a/g10/keydb.h b/g10/keydb.h
index 739376838..627564c3c 100644
--- a/g10/keydb.h
+++ b/g10/keydb.h
@@ -1,517 +1,518 @@
/* keydb.h - Key database
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
* 2006, 2010 Free Software Foundation, Inc.
* Copyright (C) 2015, 2016 g10 Code GmbH
*
* This file is part of GnuPG.
*
* GnuPG 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 3 of the License, or
* (at your option) any later version.
*
* GnuPG 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, see .
*/
#ifndef G10_KEYDB_H
#define G10_KEYDB_H
#include "../common/types.h"
#include "../common/util.h"
#include "packet.h"
/* What qualifies as a certification (rather than a signature?) */
#define IS_CERT(s) (IS_KEY_SIG(s) || IS_UID_SIG(s) || IS_SUBKEY_SIG(s) \
|| IS_KEY_REV(s) || IS_UID_REV(s) || IS_SUBKEY_REV(s))
#define IS_SIG(s) (!IS_CERT(s))
#define IS_KEY_SIG(s) ((s)->sig_class == 0x1f)
#define IS_UID_SIG(s) (((s)->sig_class & ~3) == 0x10)
#define IS_SUBKEY_SIG(s) ((s)->sig_class == 0x18)
+#define IS_BACK_SIG(s) ((s)->sig_class == 0x19)
#define IS_KEY_REV(s) ((s)->sig_class == 0x20)
#define IS_UID_REV(s) ((s)->sig_class == 0x30)
#define IS_SUBKEY_REV(s) ((s)->sig_class == 0x28)
struct getkey_ctx_s;
typedef struct getkey_ctx_s *GETKEY_CTX;
typedef struct getkey_ctx_s *getkey_ctx_t;
/****************
* A Keyblock is all packets which form an entire certificate;
* i.e. the public key, certificate, trust packets, user ids,
* signatures, and subkey.
*
* This structure is also used to bind arbitrary packets together.
*/
struct kbnode_struct {
KBNODE next;
PACKET *pkt;
int flag;
int private_flag;
ulong recno; /* used while updating the trustdb */
};
#define is_deleted_kbnode(a) ((a)->private_flag & 1)
#define is_cloned_kbnode(a) ((a)->private_flag & 2)
/* Bit flags used with build_pk_list. */
enum
{
PK_LIST_ENCRYPT_TO = 1, /* This is an encrypt-to recipient. */
PK_LIST_HIDDEN = 2, /* This is a hidden recipient. */
PK_LIST_CONFIG = 4, /* Specified via config file. */
PK_LIST_FROM_FILE = 8 /* Take key from file with that name. */
};
/* To store private data in the flags the private data must be left
* shifted by this value. */
enum
{
PK_LIST_SHIFT = 4
};
/* Structure to hold a couple of public key certificates. */
typedef struct pk_list *PK_LIST; /* Deprecated. */
typedef struct pk_list *pk_list_t;
struct pk_list
{
PK_LIST next;
PKT_public_key *pk;
int flags; /* See PK_LIST_ constants. */
};
/* Structure to hold a list of secret key certificates. */
typedef struct sk_list *SK_LIST;
struct sk_list
{
SK_LIST next;
PKT_public_key *pk;
int mark; /* not used */
};
/* structure to collect all information which can be used to
* identify a public key */
typedef struct pubkey_find_info *PUBKEY_FIND_INFO;
struct pubkey_find_info {
u32 keyid[2];
unsigned nbits;
byte pubkey_algo;
byte fingerprint[MAX_FINGERPRINT_LEN];
char userid[1];
};
/* Helper type for preference functions. */
union pref_hint
{
int digest_length;
};
/* Constants to describe from where a key was fetched or updated. */
enum
{
KEYORG_UNKNOWN = 0,
KEYORG_KS = 1, /* Public keyserver. */
KEYORG_KS_PREF = 2, /* Preferred keysrver. */
KEYORG_DANE = 3, /* OpenPGP DANE. */
KEYORG_WKD = 4, /* Web Key Directory. */
KEYORG_URL = 5, /* Trusted URL. */
KEYORG_FILE = 6, /* Trusted file. */
KEYORG_SELF = 7 /* We generated it. */
};
/*-- keydb.c --*/
#define KEYDB_RESOURCE_FLAG_PRIMARY 2 /* The primary resource. */
#define KEYDB_RESOURCE_FLAG_DEFAULT 4 /* The default one. */
#define KEYDB_RESOURCE_FLAG_READONLY 8 /* Open in read only mode. */
#define KEYDB_RESOURCE_FLAG_GPGVDEF 16 /* Default file for gpgv. */
/* Format a search term for debugging output. The caller must free
the result. */
char *keydb_search_desc_dump (struct keydb_search_desc *desc);
/* Register a resource (keyring or keybox). */
gpg_error_t keydb_add_resource (const char *url, unsigned int flags);
/* Dump some statistics to the log. */
void keydb_dump_stats (void);
/* Create a new database handle. Returns NULL on error, sets ERRNO,
and prints an error diagnostic. */
KEYDB_HANDLE keydb_new (void);
/* Free all resources owned by the database handle. */
void keydb_release (KEYDB_HANDLE hd);
/* Take a lock on the files immediately and not only during insert or
* update. This lock is released with keydb_release. */
gpg_error_t keydb_lock (KEYDB_HANDLE hd);
/* Set a flag on the handle to suppress use of cached results. This
is required for updating a keyring and for key listings. Fixme:
Using a new parameter for keydb_new might be a better solution. */
void keydb_disable_caching (KEYDB_HANDLE hd);
/* Save the last found state and invalidate the current selection. */
void keydb_push_found_state (KEYDB_HANDLE hd);
/* Restore the previous save state. */
void keydb_pop_found_state (KEYDB_HANDLE hd);
/* Return the file name of the resource. */
const char *keydb_get_resource_name (KEYDB_HANDLE hd);
/* Return the keyblock last found by keydb_search. */
gpg_error_t keydb_get_keyblock (KEYDB_HANDLE hd, KBNODE *ret_kb);
/* Update the keyblock KB. */
gpg_error_t keydb_update_keyblock (ctrl_t ctrl, KEYDB_HANDLE hd, kbnode_t kb);
/* Insert a keyblock into one of the underlying keyrings or keyboxes. */
gpg_error_t keydb_insert_keyblock (KEYDB_HANDLE hd, kbnode_t kb);
/* Delete the currently selected keyblock. */
gpg_error_t keydb_delete_keyblock (KEYDB_HANDLE hd);
/* Find the first writable resource. */
gpg_error_t keydb_locate_writable (KEYDB_HANDLE hd);
/* Rebuild the on-disk caches of all key resources. */
void keydb_rebuild_caches (ctrl_t ctrl, int noisy);
/* Return the number of skipped blocks (because they were to large to
read from a keybox) since the last search reset. */
unsigned long keydb_get_skipped_counter (KEYDB_HANDLE hd);
/* Clears the current search result and resets the handle's position. */
gpg_error_t keydb_search_reset (KEYDB_HANDLE hd);
/* Search the database for keys matching the search description. */
gpg_error_t keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
size_t ndesc, size_t *descindex);
/* Return the first non-legacy key in the database. */
gpg_error_t keydb_search_first (KEYDB_HANDLE hd);
/* Return the next key (not the next matching key!). */
gpg_error_t keydb_search_next (KEYDB_HANDLE hd);
/* This is a convenience function for searching for keys with a long
key id. */
gpg_error_t keydb_search_kid (KEYDB_HANDLE hd, u32 *kid);
/* This is a convenience function for searching for keys with a long
(20 byte) fingerprint. */
gpg_error_t keydb_search_fpr (KEYDB_HANDLE hd, const byte *fpr);
/*-- pkclist.c --*/
void show_revocation_reason (ctrl_t ctrl, PKT_public_key *pk, int mode );
int check_signatures_trust (ctrl_t ctrl, PKT_signature *sig);
void release_pk_list (PK_LIST pk_list);
int build_pk_list (ctrl_t ctrl, strlist_t rcpts, PK_LIST *ret_pk_list);
gpg_error_t find_and_check_key (ctrl_t ctrl,
const char *name, unsigned int use,
int mark_hidden, int from_file,
pk_list_t *pk_list_addr);
int algo_available( preftype_t preftype, int algo,
const union pref_hint *hint );
int select_algo_from_prefs( PK_LIST pk_list, int preftype,
int request, const union pref_hint *hint);
int select_mdc_from_pklist (PK_LIST pk_list);
void warn_missing_mdc_from_pklist (PK_LIST pk_list);
void warn_missing_aes_from_pklist (PK_LIST pk_list);
/*-- skclist.c --*/
int random_is_faked (void);
void release_sk_list( SK_LIST sk_list );
gpg_error_t build_sk_list (ctrl_t ctrl, strlist_t locusr,
SK_LIST *ret_sk_list, unsigned use);
/*-- passphrase.h --*/
unsigned char encode_s2k_iterations (int iterations);
int have_static_passphrase(void);
const char *get_static_passphrase (void);
void set_passphrase_from_string(const char *pass);
void read_passphrase_from_fd( int fd );
void passphrase_clear_cache (const char *cacheid);
DEK *passphrase_to_dek_ext(u32 *keyid, int pubkey_algo,
int cipher_algo, STRING2KEY *s2k, int mode,
const char *tryagain_text,
const char *custdesc, const char *custprompt,
int *canceled);
DEK *passphrase_to_dek (int cipher_algo, STRING2KEY *s2k,
int create, int nocache,
const char *tryagain_text, int *canceled);
void set_next_passphrase( const char *s );
char *get_last_passphrase(void);
void next_to_last_passphrase(void);
void emit_status_need_passphrase (ctrl_t ctrl, u32 *keyid,
u32 *mainkeyid, int pubkey_algo);
#define FORMAT_KEYDESC_NORMAL 0
#define FORMAT_KEYDESC_IMPORT 1
#define FORMAT_KEYDESC_EXPORT 2
#define FORMAT_KEYDESC_DELKEY 3
char *gpg_format_keydesc (ctrl_t ctrl,
PKT_public_key *pk, int mode, int escaped);
/*-- getkey.c --*/
/* Cache a copy of a public key in the public key cache. */
void cache_public_key( PKT_public_key *pk );
/* Disable and drop the public key cache. */
void getkey_disable_caches(void);
/* Return the public key with the key id KEYID and store it at PK. */
int get_pubkey (ctrl_t ctrl, PKT_public_key *pk, u32 *keyid);
/* Similar to get_pubkey, but it does not take PK->REQ_USAGE into
account nor does it merge in the self-signed data. This function
also only considers primary keys. */
int get_pubkey_fast (PKT_public_key *pk, u32 *keyid);
/* Return the key block for the key with KEYID. */
kbnode_t get_pubkeyblock (ctrl_t ctrl, u32 *keyid);
/* A list used by get_pubkeys to gather all of the matches. */
struct pubkey_s
{
struct pubkey_s *next;
/* The key to use (either the public key or the subkey). */
PKT_public_key *pk;
kbnode_t keyblock;
};
typedef struct pubkey_s *pubkey_t;
/* Free a single key. This does not remove key from any list! */
void pubkey_free (pubkey_t key);
/* Free a list of public keys. */
void pubkeys_free (pubkey_t keys);
/* Returns all keys that match the search specification SEARCH_TERMS.
The returned keys should be freed using pubkeys_free. */
gpg_error_t
get_pubkeys (ctrl_t ctrl,
char *search_terms, int use, int include_unusable, char *source,
int warn_possibly_ambiguous,
pubkey_t *r_keys);
/* Find a public key identified by NAME. */
int get_pubkey_byname (ctrl_t ctrl,
GETKEY_CTX *retctx, PKT_public_key *pk,
const char *name,
KBNODE *ret_keyblock, KEYDB_HANDLE *ret_kdbhd,
int include_unusable, int no_akl );
/* Likewise, but only return the best match if NAME resembles a mail
* address. */
gpg_error_t get_best_pubkey_byname (ctrl_t ctrl,
GETKEY_CTX *retctx, PKT_public_key *pk,
const char *name, KBNODE *ret_keyblock,
int include_unusable, int no_akl);
/* Get a public key directly from file FNAME. */
gpg_error_t get_pubkey_fromfile (ctrl_t ctrl,
PKT_public_key *pk, const char *fname);
/* Return the public key with the key id KEYID iff the secret key is
* available and store it at PK. */
gpg_error_t get_seckey (ctrl_t ctrl, PKT_public_key *pk, u32 *keyid);
/* Lookup a key with the specified fingerprint. */
int get_pubkey_byfprint (ctrl_t ctrl, PKT_public_key *pk, kbnode_t *r_keyblock,
const byte *fprint, size_t fprint_len);
/* This function is similar to get_pubkey_byfprint, but it doesn't
merge the self-signed data into the public key and subkeys or into
the user ids. */
gpg_error_t get_pubkey_byfprint_fast (PKT_public_key *pk,
const byte *fprint, size_t fprint_len);
/* This function is similar to get_pubkey_byfprint, but it doesn't
merge the self-signed data into the public key and subkeys or into
the user ids. */
gpg_error_t get_keyblock_byfprint_fast (kbnode_t *r_keyblock,
KEYDB_HANDLE *r_hd,
const byte *fprint, size_t fprint_len,
int lock);
/* Returns true if a secret key is available for the public key with
key id KEYID. */
int have_secret_key_with_kid (u32 *keyid);
/* Parse the --default-key parameter. Returns the last key (in terms
of when the option is given) that is available. */
const char *parse_def_secret_key (ctrl_t ctrl);
/* Look up a secret key. */
gpg_error_t get_seckey_default (ctrl_t ctrl, PKT_public_key *pk);
gpg_error_t get_seckey_default_or_card (ctrl_t ctrl, PKT_public_key *pk,
const byte *fpr, size_t fpr_len);
/* Search for keys matching some criteria. */
gpg_error_t getkey_bynames (ctrl_t ctrl,
getkey_ctx_t *retctx, PKT_public_key *pk,
strlist_t names, int want_secret,
kbnode_t *ret_keyblock);
/* Search for one key matching some criteria. */
gpg_error_t getkey_byname (ctrl_t ctrl,
getkey_ctx_t *retctx, PKT_public_key *pk,
const char *name, int want_secret,
kbnode_t *ret_keyblock);
/* Return the next search result. */
gpg_error_t getkey_next (ctrl_t ctrl, getkey_ctx_t ctx,
PKT_public_key *pk, kbnode_t *ret_keyblock);
/* Release any resources used by a key listing context. */
void getkey_end (ctrl_t ctrl, getkey_ctx_t ctx);
/* Return the database handle used by this context. The context still
owns the handle. */
KEYDB_HANDLE get_ctx_handle(GETKEY_CTX ctx);
/* Enumerate some secret keys. */
gpg_error_t enum_secret_keys (ctrl_t ctrl, void **context, PKT_public_key *pk);
/* Set the mainkey_id fields for all keys in KEYBLOCK. */
void setup_main_keyids (kbnode_t keyblock);
/* This function merges information from the self-signed data into the
data structures. */
void merge_keys_and_selfsig (ctrl_t ctrl, kbnode_t keyblock);
char*get_user_id_string_native (ctrl_t ctrl, u32 *keyid);
char*get_long_user_id_string (ctrl_t ctrl, u32 *keyid);
char*get_user_id (ctrl_t ctrl, u32 *keyid, size_t *rn);
char*get_user_id_native (ctrl_t ctrl, u32 *keyid);
char *get_user_id_byfpr (ctrl_t ctrl, const byte *fpr, size_t *rn);
char *get_user_id_byfpr_native (ctrl_t ctrl, const byte *fpr);
void release_akl(void);
int parse_auto_key_locate(const char *options);
int parse_key_origin (char *string);
const char *key_origin_string (int origin);
/*-- keyid.c --*/
int pubkey_letter( int algo );
char *pubkey_string (PKT_public_key *pk, char *buffer, size_t bufsize);
#define PUBKEY_STRING_SIZE 32
u32 v3_keyid (gcry_mpi_t a, u32 *ki);
void hash_public_key( gcry_md_hd_t md, PKT_public_key *pk );
char *format_keyid (u32 *keyid, int format, char *buffer, int len);
/* Return PK's keyid. The memory is owned by PK. */
u32 *pk_keyid (PKT_public_key *pk);
/* Return the keyid of the primary key associated with PK. The memory
is owned by PK. */
u32 *pk_main_keyid (PKT_public_key *pk);
/* Order A and B. If A < B then return -1, if A == B then return 0,
and if A > B then return 1. */
static int GPGRT_ATTR_UNUSED
keyid_cmp (const u32 *a, const u32 *b)
{
if (a[0] < b[0])
return -1;
if (a[0] > b[0])
return 1;
if (a[1] < b[1])
return -1;
if (a[1] > b[1])
return 1;
return 0;
}
/* Return whether PK is a primary key. */
static int GPGRT_ATTR_UNUSED
pk_is_primary (PKT_public_key *pk)
{
return keyid_cmp (pk_keyid (pk), pk_main_keyid (pk)) == 0;
}
/* Copy the keyid in SRC to DEST and return DEST. */
u32 *keyid_copy (u32 *dest, const u32 *src);
size_t keystrlen(void);
const char *keystr(u32 *keyid);
const char *keystr_with_sub (u32 *main_kid, u32 *sub_kid);
const char *keystr_from_pk(PKT_public_key *pk);
const char *keystr_from_pk_with_sub (PKT_public_key *main_pk,
PKT_public_key *sub_pk);
/* Return PK's key id as a string using the default format. PK owns
the storage. */
const char *pk_keyid_str (PKT_public_key *pk);
const char *keystr_from_desc(KEYDB_SEARCH_DESC *desc);
u32 keyid_from_pk( PKT_public_key *pk, u32 *keyid );
u32 keyid_from_sig (PKT_signature *sig, u32 *keyid );
u32 keyid_from_fingerprint (ctrl_t ctrl, const byte *fprint, size_t fprint_len,
u32 *keyid);
byte *namehash_from_uid(PKT_user_id *uid);
unsigned nbits_from_pk( PKT_public_key *pk );
/* Convert an UTC TIMESTAMP into an UTC yyyy-mm-dd string. Return
* that string. The caller should pass a buffer with at least a size
* of MK_DATESTR_SIZE. */
char *mk_datestr (char *buffer, size_t bufsize, u32 timestamp);
#define MK_DATESTR_SIZE 11
const char *datestr_from_pk( PKT_public_key *pk );
const char *datestr_from_sig( PKT_signature *sig );
const char *expirestr_from_pk( PKT_public_key *pk );
const char *expirestr_from_sig( PKT_signature *sig );
const char *revokestr_from_pk( PKT_public_key *pk );
const char *usagestr_from_pk (PKT_public_key *pk, int fill);
const char *colon_strtime (u32 t);
const char *colon_datestr_from_pk (PKT_public_key *pk);
const char *colon_datestr_from_sig (PKT_signature *sig);
const char *colon_expirestr_from_sig (PKT_signature *sig);
byte *fingerprint_from_pk( PKT_public_key *pk, byte *buf, size_t *ret_len );
char *hexfingerprint (PKT_public_key *pk, char *buffer, size_t buflen);
char *format_hexfingerprint (const char *fingerprint,
char *buffer, size_t buflen);
gpg_error_t keygrip_from_pk (PKT_public_key *pk, unsigned char *array);
gpg_error_t hexkeygrip_from_pk (PKT_public_key *pk, char **r_grip);
/*-- kbnode.c --*/
KBNODE new_kbnode( PACKET *pkt );
KBNODE clone_kbnode( KBNODE node );
void release_kbnode( KBNODE n );
void delete_kbnode( KBNODE node );
void add_kbnode( KBNODE root, KBNODE node );
void insert_kbnode( KBNODE root, KBNODE node, int pkttype );
void move_kbnode( KBNODE *root, KBNODE node, KBNODE where );
void remove_kbnode( KBNODE *root, KBNODE node );
KBNODE find_prev_kbnode( KBNODE root, KBNODE node, int pkttype );
KBNODE find_next_kbnode( KBNODE node, int pkttype );
KBNODE find_kbnode( KBNODE node, int pkttype );
KBNODE walk_kbnode( KBNODE root, KBNODE *context, int all );
void clear_kbnode_flags( KBNODE n );
int commit_kbnode( KBNODE *root );
void dump_kbnode( KBNODE node );
#endif /*G10_KEYDB_H*/
diff --git a/g10/sig-check.c b/g10/sig-check.c
index 23af12b2e..1a90fd326 100644
--- a/g10/sig-check.c
+++ b/g10/sig-check.c
@@ -1,1177 +1,1161 @@
/* sig-check.c - Check a signature
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003,
* 2004, 2006 Free Software Foundation, Inc.
* Copyright (C) 2015, 2016 g10 Code GmbH
*
* This file is part of GnuPG.
*
* GnuPG 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 3 of the License, or
* (at your option) any later version.
*
* GnuPG 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, see .
*/
#include
#include
#include
#include
#include "gpg.h"
#include "../common/util.h"
#include "packet.h"
#include "keydb.h"
#include "main.h"
#include "../common/status.h"
#include "../common/i18n.h"
#include "options.h"
#include "pkglue.h"
#include "../common/compliance.h"
static int check_signature_end (PKT_public_key *pk, PKT_signature *sig,
gcry_md_hd_t digest,
int *r_expired, int *r_revoked,
PKT_public_key *ret_pk);
static int check_signature_end_simple (PKT_public_key *pk, PKT_signature *sig,
gcry_md_hd_t digest);
/* Statistics for signature verification. */
struct
{
unsigned int total; /* Total number of verifications. */
unsigned int cached; /* Number of seen cache entries. */
unsigned int goodsig;/* Number of good verifications from the cache. */
unsigned int badsig; /* Number of bad verifications from the cache. */
} cache_stats;
/* Dump verification stats. */
void
sig_check_dump_stats (void)
{
log_info ("sig_cache: total=%u cached=%u good=%u bad=%u\n",
cache_stats.total, cache_stats.cached,
cache_stats.goodsig, cache_stats.badsig);
}
/* Check a signature. This is shorthand for check_signature2 with
the unnamed arguments passed as NULL. */
int
check_signature (ctrl_t ctrl, PKT_signature *sig, gcry_md_hd_t digest)
{
return check_signature2 (ctrl, sig, digest, NULL, NULL, NULL, NULL);
}
/* Check a signature.
*
* Looks up the public key that created the signature (SIG->KEYID)
* from the key db. Makes sure that the signature is valid (it was
* not created prior to the key, the public key was created in the
* past, and the signature does not include any unsupported critical
* features), finishes computing the hash of the signature data, and
* checks that the signature verifies the digest. If the key that
* generated the signature is a subkey, this function also verifies
* that there is a valid backsig from the subkey to the primary key.
* Finally, if status fd is enabled and the signature class is 0x00 or
* 0x01, then a STATUS_SIG_ID is emitted on the status fd.
*
* SIG is the signature to check.
*
* DIGEST contains a valid hash context that already includes the
* signed data. This function adds the relevant meta-data from the
* signature packet to compute the final hash. (See Section 5.2 of
* RFC 4880: "The concatenation of the data being signed and the
* signature data from the version number through the hashed subpacket
* data (inclusive) is hashed.")
*
* If R_EXPIREDATE is not NULL, R_EXPIREDATE is set to the key's
* expiry.
*
* If R_EXPIRED is not NULL, *R_EXPIRED is set to 1 if PK has expired
* (0 otherwise). Note: PK being expired does not cause this function
* to fail.
*
* If R_REVOKED is not NULL, *R_REVOKED is set to 1 if PK has been
* revoked (0 otherwise). Note: PK being revoked does not cause this
* function to fail.
*
* If R_PK is not NULL, the public key is stored at that address if it
* was found; other wise NULL is stored.
*
* Returns 0 on success. An error code otherwise. */
gpg_error_t
check_signature2 (ctrl_t ctrl,
PKT_signature *sig, gcry_md_hd_t digest, u32 *r_expiredate,
int *r_expired, int *r_revoked, PKT_public_key **r_pk)
{
- int rc=0;
- PKT_public_key *pk;
-
- if (r_expiredate)
- *r_expiredate = 0;
- if (r_expired)
- *r_expired = 0;
- if (r_revoked)
- *r_revoked = 0;
- if (r_pk)
- *r_pk = NULL;
-
- pk = xtrycalloc (1, sizeof *pk);
- if (!pk)
- return gpg_error_from_syserror ();
-
- if ( (rc=openpgp_md_test_algo(sig->digest_algo)) )
- ; /* We don't have this digest. */
- else if (! gnupg_digest_is_allowed (opt.compliance, 0, sig->digest_algo))
- {
- /* Compliance failure. */
- log_info (_("digest algorithm '%s' may not be used in %s mode\n"),
- gcry_md_algo_name (sig->digest_algo),
- gnupg_compliance_option_string (opt.compliance));
- rc = gpg_error (GPG_ERR_DIGEST_ALGO);
- }
- else if ((rc=openpgp_pk_test_algo(sig->pubkey_algo)))
- ; /* We don't have this pubkey algo. */
- else if (!gcry_md_is_enabled (digest,sig->digest_algo))
- {
- /* Sanity check that the md has a context for the hash that the
- sig is expecting. This can happen if a onepass sig header does
- not match the actual sig, and also if the clearsign "Hash:"
- header is missing or does not match the actual sig. */
+ int rc=0;
+ PKT_public_key *pk;
- log_info(_("WARNING: signature digest conflict in message\n"));
- rc = gpg_error (GPG_ERR_GENERAL);
- }
- else if( get_pubkey (ctrl, pk, sig->keyid ) )
- rc = gpg_error (GPG_ERR_NO_PUBKEY);
- else if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_VERIFICATION,
- pk->pubkey_algo, pk->pkey,
- nbits_from_pk (pk),
- NULL))
- {
- /* Compliance failure. */
- log_error (_("key %s may not be used for signing in %s mode\n"),
- keystr_from_pk (pk),
- gnupg_compliance_option_string (opt.compliance));
- rc = gpg_error (GPG_ERR_PUBKEY_ALGO);
- }
- else if(!pk->flags.valid)
- {
- /* You cannot have a good sig from an invalid key. */
- rc = gpg_error (GPG_ERR_BAD_PUBKEY);
- }
- else
- {
- if(r_expiredate)
- *r_expiredate = pk->expiredate;
-
- rc = check_signature_end (pk, sig, digest, r_expired, r_revoked, NULL);
-
- /* Check the backsig. This is a 0x19 signature from the
- subkey on the primary key. The idea here is that it should
- not be possible for someone to "steal" subkeys and claim
- them as their own. The attacker couldn't actually use the
- subkey, but they could try and claim ownership of any
- signatures issued by it. */
- if (!rc && !pk->flags.primary && pk->flags.backsig < 2)
- {
- if (!pk->flags.backsig)
- {
- log_info(_("WARNING: signing subkey %s is not"
- " cross-certified\n"),keystr_from_pk(pk));
- log_info(_("please see %s for more information\n"),
- "https://gnupg.org/faq/subkey-cross-certify.html");
- /* --require-cross-certification makes this warning an
- error. TODO: change the default to require this
- after more keys have backsigs. */
- if(opt.flags.require_cross_cert)
- rc = gpg_error (GPG_ERR_GENERAL);
- }
- else if(pk->flags.backsig == 1)
- {
- log_info(_("WARNING: signing subkey %s has an invalid"
- " cross-certification\n"),keystr_from_pk(pk));
- rc = gpg_error (GPG_ERR_GENERAL);
- }
- }
+ if (r_expiredate)
+ *r_expiredate = 0;
+ if (r_expired)
+ *r_expired = 0;
+ if (r_revoked)
+ *r_revoked = 0;
+ if (r_pk)
+ *r_pk = NULL;
- }
+ pk = xtrycalloc (1, sizeof *pk);
+ if (!pk)
+ return gpg_error_from_syserror ();
- if( !rc && sig->sig_class < 2 && is_status_enabled() ) {
- /* This signature id works best with DLP algorithms because
- * they use a random parameter for every signature. Instead of
- * this sig-id we could have also used the hash of the document
- * and the timestamp, but the drawback of this is, that it is
- * not possible to sign more than one identical document within
- * one second. Some remote batch processing applications might
- * like this feature here.
- *
- * Note that before 2.0.10, we used RIPE-MD160 for the hash
- * and accidentally didn't include the timestamp and algorithm
- * information in the hash. Given that this feature is not
- * commonly used and that a replay attacks detection should
- * not solely be based on this feature (because it does not
- * work with RSA), we take the freedom and switch to SHA-1
- * with 2.0.10 to take advantage of hardware supported SHA-1
- * implementations. We also include the missing information
- * in the hash. Note also the SIG_ID as computed by gpg 1.x
- * and gpg 2.x didn't matched either because 2.x used to print
- * MPIs not in PGP format. */
- u32 a = sig->timestamp;
- int nsig = pubkey_get_nsig( sig->pubkey_algo );
- unsigned char *p, *buffer;
- size_t n, nbytes;
- int i;
- char hashbuf[20];
-
- nbytes = 6;
- for (i=0; i < nsig; i++ )
- {
- if (gcry_mpi_print (GCRYMPI_FMT_USG, NULL, 0, &n, sig->data[i]))
- BUG();
- nbytes += n;
- }
+ if ((rc=openpgp_md_test_algo(sig->digest_algo)))
+ {
+ /* We don't have this digest. */
+ }
+ else if (!gnupg_digest_is_allowed (opt.compliance, 0, sig->digest_algo))
+ {
+ /* Compliance failure. */
+ log_info (_("digest algorithm '%s' may not be used in %s mode\n"),
+ gcry_md_algo_name (sig->digest_algo),
+ gnupg_compliance_option_string (opt.compliance));
+ rc = gpg_error (GPG_ERR_DIGEST_ALGO);
+ }
+ else if ((rc=openpgp_pk_test_algo(sig->pubkey_algo)))
+ {
+ /* We don't have this pubkey algo. */
+ }
+ else if (!gcry_md_is_enabled (digest,sig->digest_algo))
+ {
+ /* Sanity check that the md has a context for the hash that the
+ * sig is expecting. This can happen if a onepass sig header
+ * does not match the actual sig, and also if the clearsign
+ * "Hash:" header is missing or does not match the actual sig. */
+ log_info(_("WARNING: signature digest conflict in message\n"));
+ rc = gpg_error (GPG_ERR_GENERAL);
+ }
+ else if (get_pubkey (ctrl, pk, sig->keyid))
+ rc = gpg_error (GPG_ERR_NO_PUBKEY);
+ else if (!gnupg_pk_is_allowed (opt.compliance, PK_USE_VERIFICATION,
+ pk->pubkey_algo, pk->pkey,
+ nbits_from_pk (pk),
+ NULL))
+ {
+ /* Compliance failure. */
+ log_error (_("key %s may not be used for signing in %s mode\n"),
+ keystr_from_pk (pk),
+ gnupg_compliance_option_string (opt.compliance));
+ rc = gpg_error (GPG_ERR_PUBKEY_ALGO);
+ }
+ else if (!pk->flags.valid)
+ {
+ /* You cannot have a good sig from an invalid key. */
+ rc = gpg_error (GPG_ERR_BAD_PUBKEY);
+ }
+ else
+ {
+ if (r_expiredate)
+ *r_expiredate = pk->expiredate;
+
+ rc = check_signature_end (pk, sig, digest, r_expired, r_revoked, NULL);
+
+ /* Check the backsig. This is a back signature (0x19) from
+ * the subkey on the primary key. The idea here is that it
+ * should not be possible for someone to "steal" subkeys and
+ * claim them as their own. The attacker couldn't actually
+ * use the subkey, but they could try and claim ownership of
+ * any signatures issued by it. */
+ if (!rc && !pk->flags.primary && pk->flags.backsig < 2)
+ {
+ if (!pk->flags.backsig)
+ {
+ log_info (_("WARNING: signing subkey %s is not"
+ " cross-certified\n"),keystr_from_pk(pk));
+ log_info (_("please see %s for more information\n"),
+ "https://gnupg.org/faq/subkey-cross-certify.html");
+ /* The default option --require-cross-certification
+ * makes this warning an error. */
+ if (opt.flags.require_cross_cert)
+ rc = gpg_error (GPG_ERR_GENERAL);
+ }
+ else if(pk->flags.backsig == 1)
+ {
+ log_info (_("WARNING: signing subkey %s has an invalid"
+ " cross-certification\n"), keystr_from_pk(pk));
+ rc = gpg_error (GPG_ERR_GENERAL);
+ }
+ }
- /* Make buffer large enough to be later used as output buffer. */
- if (nbytes < 100)
- nbytes = 100;
- nbytes += 10; /* Safety margin. */
-
- /* Fill and hash buffer. */
- buffer = p = xmalloc (nbytes);
- *p++ = sig->pubkey_algo;
- *p++ = sig->digest_algo;
- *p++ = (a >> 24) & 0xff;
- *p++ = (a >> 16) & 0xff;
- *p++ = (a >> 8) & 0xff;
- *p++ = a & 0xff;
- nbytes -= 6;
- for (i=0; i < nsig; i++ )
- {
- if (gcry_mpi_print (GCRYMPI_FMT_PGP, p, nbytes, &n, sig->data[i]))
- BUG();
- p += n;
- nbytes -= n;
- }
- gcry_md_hash_buffer (GCRY_MD_SHA1, hashbuf, buffer, p-buffer);
-
- p = make_radix64_string (hashbuf, 20);
- sprintf (buffer, "%s %s %lu",
- p, strtimestamp (sig->timestamp), (ulong)sig->timestamp);
- xfree (p);
- write_status_text (STATUS_SIG_ID, buffer);
- xfree (buffer);
}
- if (r_pk)
- *r_pk = pk;
- else
- {
- release_public_key_parts (pk);
- xfree (pk);
- }
+ if (!rc && sig->sig_class < 2 && is_status_enabled ())
+ {
+ /* This signature id works best with DLP algorithms because
+ * they use a random parameter for every signature. Instead of
+ * this sig-id we could have also used the hash of the document
+ * and the timestamp, but the drawback of this is, that it is
+ * not possible to sign more than one identical document within
+ * one second. Some remote batch processing applications might
+ * like this feature here.
+ *
+ * Note that before 2.0.10, we used RIPE-MD160 for the hash
+ * and accidentally didn't include the timestamp and algorithm
+ * information in the hash. Given that this feature is not
+ * commonly used and that a replay attacks detection should
+ * not solely be based on this feature (because it does not
+ * work with RSA), we take the freedom and switch to SHA-1
+ * with 2.0.10 to take advantage of hardware supported SHA-1
+ * implementations. We also include the missing information
+ * in the hash. Note also the SIG_ID as computed by gpg 1.x
+ * and gpg 2.x didn't matched either because 2.x used to print
+ * MPIs not in PGP format. */
+ u32 a = sig->timestamp;
+ int nsig = pubkey_get_nsig (sig->pubkey_algo);
+ unsigned char *p, *buffer;
+ size_t n, nbytes;
+ int i;
+ char hashbuf[20];
+
+ nbytes = 6;
+ for (i=0; i < nsig; i++ )
+ {
+ if (gcry_mpi_print (GCRYMPI_FMT_USG, NULL, 0, &n, sig->data[i]))
+ BUG();
+ nbytes += n;
+ }
- return rc;
+ /* Make buffer large enough to be later used as output buffer. */
+ if (nbytes < 100)
+ nbytes = 100;
+ nbytes += 10; /* Safety margin. */
+
+ /* Fill and hash buffer. */
+ buffer = p = xmalloc (nbytes);
+ *p++ = sig->pubkey_algo;
+ *p++ = sig->digest_algo;
+ *p++ = (a >> 24) & 0xff;
+ *p++ = (a >> 16) & 0xff;
+ *p++ = (a >> 8) & 0xff;
+ *p++ = a & 0xff;
+ nbytes -= 6;
+ for (i=0; i < nsig; i++ )
+ {
+ if (gcry_mpi_print (GCRYMPI_FMT_PGP, p, nbytes, &n, sig->data[i]))
+ BUG();
+ p += n;
+ nbytes -= n;
+ }
+ gcry_md_hash_buffer (GCRY_MD_SHA1, hashbuf, buffer, p-buffer);
+
+ p = make_radix64_string (hashbuf, 20);
+ sprintf (buffer, "%s %s %lu",
+ p, strtimestamp (sig->timestamp), (ulong)sig->timestamp);
+ xfree (p);
+ write_status_text (STATUS_SIG_ID, buffer);
+ xfree (buffer);
+ }
+
+ if (r_pk)
+ *r_pk = pk;
+ else
+ {
+ release_public_key_parts (pk);
+ xfree (pk);
+ }
+
+ return rc;
}
/* The signature SIG was generated with the public key PK. Check
* whether the signature is valid in the following sense:
*
* - Make sure the public key was created before the signature was
* generated.
*
* - Make sure the public key was created in the past
*
* - Check whether PK has expired (set *R_EXPIRED to 1 if so and 0
* otherwise)
*
* - Check whether PK has been revoked (set *R_REVOKED to 1 if so
* and 0 otherwise).
*
* If either of the first two tests fail, returns an error code.
* Otherwise returns 0. (Thus, this function doesn't fail if the
* public key is expired or revoked.) */
static int
check_signature_metadata_validity (PKT_public_key *pk, PKT_signature *sig,
int *r_expired, int *r_revoked)
{
- u32 cur_time;
+ u32 cur_time;
- if(r_expired)
- *r_expired = 0;
- if(r_revoked)
- *r_revoked = 0;
+ if (r_expired)
+ *r_expired = 0;
+ if (r_revoked)
+ *r_revoked = 0;
- if( pk->timestamp > sig->timestamp )
- {
- ulong d = pk->timestamp - sig->timestamp;
- if ( d < 86400 )
- {
- log_info
- (ngettext
- ("public key %s is %lu second newer than the signature\n",
- "public key %s is %lu seconds newer than the signature\n",
- d), keystr_from_pk (pk), d);
- }
- else
- {
- d /= 86400;
- log_info
- (ngettext
- ("public key %s is %lu day newer than the signature\n",
- "public key %s is %lu days newer than the signature\n",
- d), keystr_from_pk (pk), d);
- }
- if (!opt.ignore_time_conflict)
- return GPG_ERR_TIME_CONFLICT; /* pubkey newer than signature. */
- }
+ if (pk->timestamp > sig->timestamp )
+ {
+ ulong d = pk->timestamp - sig->timestamp;
+ if ( d < 86400 )
+ {
+ log_info (ngettext
+ ("public key %s is %lu second newer than the signature\n",
+ "public key %s is %lu seconds newer than the signature\n",
+ d), keystr_from_pk (pk), d);
+ }
+ else
+ {
+ d /= 86400;
+ log_info (ngettext
+ ("public key %s is %lu day newer than the signature\n",
+ "public key %s is %lu days newer than the signature\n",
+ d), keystr_from_pk (pk), d);
+ }
+ if (!opt.ignore_time_conflict)
+ return GPG_ERR_TIME_CONFLICT; /* pubkey newer than signature. */
+ }
- cur_time = make_timestamp();
- if( pk->timestamp > cur_time )
- {
- ulong d = pk->timestamp - cur_time;
- if (d < 86400)
- {
- log_info (ngettext("key %s was created %lu second"
- " in the future (time warp or clock problem)\n",
- "key %s was created %lu seconds"
- " in the future (time warp or clock problem)\n",
- d), keystr_from_pk (pk), d);
- }
- else
- {
- d /= 86400;
- log_info (ngettext("key %s was created %lu day"
- " in the future (time warp or clock problem)\n",
- "key %s was created %lu days"
- " in the future (time warp or clock problem)\n",
- d), keystr_from_pk (pk), d);
- }
- if (!opt.ignore_time_conflict)
- return GPG_ERR_TIME_CONFLICT;
- }
+ cur_time = make_timestamp ();
+ if (pk->timestamp > cur_time)
+ {
+ ulong d = pk->timestamp - cur_time;
+ if (d < 86400)
+ {
+ log_info (ngettext("key %s was created %lu second"
+ " in the future (time warp or clock problem)\n",
+ "key %s was created %lu seconds"
+ " in the future (time warp or clock problem)\n",
+ d), keystr_from_pk (pk), d);
+ }
+ else
+ {
+ d /= 86400;
+ log_info (ngettext("key %s was created %lu day"
+ " in the future (time warp or clock problem)\n",
+ "key %s was created %lu days"
+ " in the future (time warp or clock problem)\n",
+ d), keystr_from_pk (pk), d);
+ }
+ if (!opt.ignore_time_conflict)
+ return GPG_ERR_TIME_CONFLICT;
+ }
- /* Check whether the key has expired. We check the has_expired
- flag which is set after a full evaluation of the key (getkey.c)
- as well as a simple compare to the current time in case the
- merge has for whatever reasons not been done. */
- if( pk->has_expired || (pk->expiredate && pk->expiredate < cur_time)) {
- char buf[11];
- if (opt.verbose)
- log_info(_("Note: signature key %s expired %s\n"),
- keystr_from_pk(pk), asctimestamp( pk->expiredate ) );
- sprintf(buf,"%lu",(ulong)pk->expiredate);
- write_status_text(STATUS_KEYEXPIRED,buf);
- if(r_expired)
- *r_expired = 1;
+ /* Check whether the key has expired. We check the has_expired
+ * flag which is set after a full evaluation of the key (getkey.c)
+ * as well as a simple compare to the current time in case the
+ * merge has for whatever reasons not been done. */
+ if (pk->has_expired || (pk->expiredate && pk->expiredate < cur_time))
+ {
+ char buf[11];
+ if (opt.verbose)
+ log_info (_("Note: signature key %s expired %s\n"),
+ keystr_from_pk(pk), asctimestamp( pk->expiredate ) );
+ snprintf (buf, sizeof buf, "%lu",(ulong)pk->expiredate);
+ write_status_text (STATUS_KEYEXPIRED, buf);
+ if (r_expired)
+ *r_expired = 1;
}
- if (pk->flags.revoked)
- {
- if (opt.verbose)
- log_info (_("Note: signature key %s has been revoked\n"),
- keystr_from_pk(pk));
- if (r_revoked)
- *r_revoked=1;
- }
+ if (pk->flags.revoked)
+ {
+ if (opt.verbose)
+ log_info (_("Note: signature key %s has been revoked\n"),
+ keystr_from_pk(pk));
+ if (r_revoked)
+ *r_revoked=1;
+ }
- return 0;
+ return 0;
}
/* Finish generating a signature and check it. Concretely: make sure
* that the signature is valid (it was not created prior to the key,
* the public key was created in the past, and the signature does not
* include any unsupported critical features), finish computing the
* digest by adding the relevant data from the signature packet, and
* check that the signature verifies the digest.
*
* DIGEST contains a hash context, which has already hashed the signed
* data. This function adds the relevant meta-data from the signature
* packet to compute the final hash. (See Section 5.2 of RFC 4880:
* "The concatenation of the data being signed and the signature data
* from the version number through the hashed subpacket data
* (inclusive) is hashed.")
*
* SIG is the signature to check.
*
* PK is the public key used to generate the signature.
*
* If R_EXPIRED is not NULL, *R_EXPIRED is set to 1 if PK has expired
* (0 otherwise). Note: PK being expired does not cause this function
* to fail.
*
* If R_REVOKED is not NULL, *R_REVOKED is set to 1 if PK has been
* revoked (0 otherwise). Note: PK being revoked does not cause this
* function to fail.
*
* If RET_PK is not NULL, PK is copied into RET_PK on success.
*
* Returns 0 on success. An error code other. */
static int
check_signature_end (PKT_public_key *pk, PKT_signature *sig,
gcry_md_hd_t digest,
int *r_expired, int *r_revoked, PKT_public_key *ret_pk)
{
- int rc = 0;
+ int rc = 0;
- if ((rc = check_signature_metadata_validity (pk, sig,
- r_expired, r_revoked)))
- return rc;
+ if ((rc = check_signature_metadata_validity (pk, sig,
+ r_expired, r_revoked)))
+ return rc;
- if ((rc = check_signature_end_simple (pk, sig, digest)))
- return rc;
+ if ((rc = check_signature_end_simple (pk, sig, digest)))
+ return rc;
- if(!rc && ret_pk)
- copy_public_key(ret_pk,pk);
+ if (!rc && ret_pk)
+ copy_public_key(ret_pk,pk);
- return rc;
+ return rc;
}
+
/* This function is similar to check_signature_end, but it only checks
- whether the signature was generated by PK. It does not check
- expiration, revocation, etc. */
+ * whether the signature was generated by PK. It does not check
+ * expiration, revocation, etc. */
static int
check_signature_end_simple (PKT_public_key *pk, PKT_signature *sig,
gcry_md_hd_t digest)
{
- gcry_mpi_t result = NULL;
- int rc = 0;
- const struct weakhash *weak;
+ gcry_mpi_t result = NULL;
+ int rc = 0;
+ const struct weakhash *weak;
- if (!opt.flags.allow_weak_digest_algos)
+ if (!opt.flags.allow_weak_digest_algos)
+ {
for (weak = opt.weak_digests; weak; weak = weak->next)
if (sig->digest_algo == weak->algo)
{
print_digest_rejected_note(sig->digest_algo);
return GPG_ERR_DIGEST_ALGO;
}
+ }
+
+ /* Make sure the digest algo is enabled (in case of a detached
+ * signature). */
+ gcry_md_enable (digest, sig->digest_algo);
+
+ /* Complete the digest. */
+ if (sig->version >= 4)
+ gcry_md_putc (digest, sig->version);
- /* Make sure the digest algo is enabled (in case of a detached
- signature). */
- gcry_md_enable (digest, sig->digest_algo);
-
- /* Complete the digest. */
- if( sig->version >= 4 )
- gcry_md_putc( digest, sig->version );
- gcry_md_putc( digest, sig->sig_class );
- if( sig->version < 4 ) {
- u32 a = sig->timestamp;
- gcry_md_putc( digest, (a >> 24) & 0xff );
- gcry_md_putc( digest, (a >> 16) & 0xff );
- gcry_md_putc( digest, (a >> 8) & 0xff );
- gcry_md_putc( digest, a & 0xff );
+ gcry_md_putc( digest, sig->sig_class );
+ if (sig->version < 4)
+ {
+ u32 a = sig->timestamp;
+ gcry_md_putc (digest, ((a >> 24) & 0xff));
+ gcry_md_putc (digest, ((a >> 16) & 0xff));
+ gcry_md_putc (digest, ((a >> 8) & 0xff));
+ gcry_md_putc (digest, ( a & 0xff));
}
- else {
- byte buf[6];
- size_t n;
- gcry_md_putc( digest, sig->pubkey_algo );
- gcry_md_putc( digest, sig->digest_algo );
- if( sig->hashed ) {
- n = sig->hashed->len;
- gcry_md_putc (digest, (n >> 8) );
- gcry_md_putc (digest, n );
- gcry_md_write (digest, sig->hashed->data, n);
- n += 6;
+ else
+ {
+ byte buf[6];
+ size_t n;
+ gcry_md_putc (digest, sig->pubkey_algo);
+ gcry_md_putc (digest, sig->digest_algo);
+ if (sig->hashed)
+ {
+ n = sig->hashed->len;
+ gcry_md_putc (digest, (n >> 8) );
+ gcry_md_putc (digest, n );
+ gcry_md_write (digest, sig->hashed->data, n);
+ n += 6;
}
- else {
+ else
+ {
/* Two octets for the (empty) length of the hashed
- section. */
+ * section. */
gcry_md_putc (digest, 0);
gcry_md_putc (digest, 0);
n = 6;
}
- /* add some magic per Section 5.2.4 of RFC 4880. */
- buf[0] = sig->version;
- buf[1] = 0xff;
- buf[2] = n >> 24;
- buf[3] = n >> 16;
- buf[4] = n >> 8;
- buf[5] = n;
- gcry_md_write( digest, buf, 6 );
+ /* Add some magic per Section 5.2.4 of RFC 4880. */
+ buf[0] = sig->version;
+ buf[1] = 0xff;
+ buf[2] = n >> 24;
+ buf[3] = n >> 16;
+ buf[4] = n >> 8;
+ buf[5] = n;
+ gcry_md_write( digest, buf, 6 );
}
- gcry_md_final( digest );
+ gcry_md_final( digest );
- /* Convert the digest to an MPI. */
- result = encode_md_value (pk, digest, sig->digest_algo );
- if (!result)
- return GPG_ERR_GENERAL;
+ /* Convert the digest to an MPI. */
+ result = encode_md_value (pk, digest, sig->digest_algo );
+ if (!result)
+ return GPG_ERR_GENERAL;
- /* Verify the signature. */
- rc = pk_verify( pk->pubkey_algo, result, sig->data, pk->pkey );
- gcry_mpi_release (result);
+ /* Verify the signature. */
+ rc = pk_verify (pk->pubkey_algo, result, sig->data, pk->pkey);
+ gcry_mpi_release (result);
- if( !rc && sig->flags.unknown_critical )
- {
- log_info(_("assuming bad signature from key %s"
- " due to an unknown critical bit\n"),keystr_from_pk(pk));
- rc = GPG_ERR_BAD_SIGNATURE;
- }
+ if (!rc && sig->flags.unknown_critical)
+ {
+ log_info(_("assuming bad signature from key %s"
+ " due to an unknown critical bit\n"),keystr_from_pk(pk));
+ rc = GPG_ERR_BAD_SIGNATURE;
+ }
- return rc;
+ return rc;
}
/* Add a uid node to a hash context. See section 5.2.4, paragraph 4
- of RFC 4880. */
+ * of RFC 4880. */
static void
hash_uid_packet (PKT_user_id *uid, gcry_md_hd_t md, PKT_signature *sig )
{
- if( uid->attrib_data ) {
- if( sig->version >=4 ) {
- byte buf[5];
- buf[0] = 0xd1; /* packet of type 17 */
- buf[1] = uid->attrib_len >> 24; /* always use 4 length bytes */
- buf[2] = uid->attrib_len >> 16;
- buf[3] = uid->attrib_len >> 8;
- buf[4] = uid->attrib_len;
- gcry_md_write( md, buf, 5 );
+ if (uid->attrib_data)
+ {
+ if (sig->version >=4)
+ {
+ byte buf[5];
+ buf[0] = 0xd1; /* packet of type 17 */
+ buf[1] = uid->attrib_len >> 24; /* always use 4 length bytes */
+ buf[2] = uid->attrib_len >> 16;
+ buf[3] = uid->attrib_len >> 8;
+ buf[4] = uid->attrib_len;
+ gcry_md_write( md, buf, 5 );
}
- gcry_md_write( md, uid->attrib_data, uid->attrib_len );
+ gcry_md_write( md, uid->attrib_data, uid->attrib_len );
}
- else {
- if( sig->version >=4 ) {
- byte buf[5];
- buf[0] = 0xb4; /* indicates a userid packet */
- buf[1] = uid->len >> 24; /* always use 4 length bytes */
- buf[2] = uid->len >> 16;
- buf[3] = uid->len >> 8;
- buf[4] = uid->len;
- gcry_md_write( md, buf, 5 );
+ else
+ {
+ if (sig->version >=4)
+ {
+ byte buf[5];
+ buf[0] = 0xb4; /* indicates a userid packet */
+ buf[1] = uid->len >> 24; /* always use 4 length bytes */
+ buf[2] = uid->len >> 16;
+ buf[3] = uid->len >> 8;
+ buf[4] = uid->len;
+ gcry_md_write( md, buf, 5 );
}
- gcry_md_write( md, uid->name, uid->len );
+ gcry_md_write( md, uid->name, uid->len );
}
}
static void
cache_sig_result ( PKT_signature *sig, int result )
{
- if ( !result ) {
- sig->flags.checked = 1;
- sig->flags.valid = 1;
+ if (!result)
+ {
+ sig->flags.checked = 1;
+ sig->flags.valid = 1;
}
- else if ( gpg_err_code (result) == GPG_ERR_BAD_SIGNATURE ) {
- sig->flags.checked = 1;
- sig->flags.valid = 0;
+ else if (gpg_err_code (result) == GPG_ERR_BAD_SIGNATURE)
+ {
+ sig->flags.checked = 1;
+ sig->flags.valid = 0;
}
- else {
- sig->flags.checked = 0;
- sig->flags.valid = 0;
+ else
+ {
+ sig->flags.checked = 0;
+ sig->flags.valid = 0;
}
}
/* SIG is a key revocation signature. Check if this signature was
* generated by any of the public key PK's designated revokers.
*
* PK is the public key that SIG allegedly revokes.
*
* SIG is the revocation signature to check.
*
* This function avoids infinite recursion, which can happen if two
* keys are designed revokers for each other and they revoke each
* other. This is done by observing that if a key A is revoked by key
* B we still consider the revocation to be valid even if B is
* revoked. Thus, we don't need to determine whether B is revoked to
* determine whether A has been revoked by B, we just need to check
* the signature.
*
* Returns 0 if sig is valid (i.e. pk is revoked), non-0 if not
* revoked. We are careful to make sure that GPG_ERR_NO_PUBKEY is
* only returned when a revocation signature is from a valid
* revocation key designated in a revkey subpacket, but the revocation
* key itself isn't present.
*
* XXX: This code will need to be modified if gpg ever becomes
* multi-threaded. Note that this guarantees that a designated
* revocation sig will never be considered valid unless it is actually
* valid, as well as being issued by a revocation key in a valid
* direct signature. Note also that this is written so that a revoked
* revoker can still issue revocations: i.e. If A revokes B, but A is
* revoked, B is still revoked. I'm not completely convinced this is
* the proper behavior, but it matches how PGP does it. -dms */
int
check_revocation_keys (ctrl_t ctrl, PKT_public_key *pk, PKT_signature *sig)
{
static int busy=0;
int i;
int rc = GPG_ERR_GENERAL;
log_assert (IS_KEY_REV(sig));
log_assert ((sig->keyid[0]!=pk->keyid[0]) || (sig->keyid[0]!=pk->keyid[1]));
/* Avoid infinite recursion. Consider the following:
*
* - We want to check if A is revoked.
*
* - C is a designated revoker for B and has revoked B.
*
* - B is a designated revoker for A and has revoked A.
*
* When checking if A is revoked (in merge_selfsigs_main), we
* observe that A has a designed revoker. As such, we call this
* function. This function sees that there is a valid revocation
* signature, which is signed by B. It then calls check_signature()
* to verify that the signature is good. To check the sig, we need
* to lookup B. Looking up B means calling merge_selfsigs_main,
* which checks whether B is revoked, which calls this function to
* see if B was revoked by some key.
*
* In this case, the added level of indirection doesn't hurt. It
* just means a bit more work. However, if C == A, then we'd end up
* in a loop. But, it doesn't make sense to look up C anyways: even
* if B is revoked, we conservatively consider a valid revocation
* signed by B to revoke A. Since this is the only place where this
* type of recursion can occur, we simply cause this function to
* fail if it is entered recursively. */
if (busy)
{
/* Return an error (i.e. not revoked), but mark the pk as
uncacheable as we don't really know its revocation status
until it is checked directly. */
pk->flags.dont_cache = 1;
return rc;
}
busy=1;
/* es_printf("looking at %08lX with a sig from %08lX\n",(ulong)pk->keyid[1],
(ulong)sig->keyid[1]); */
/* is the issuer of the sig one of our revokers? */
if( !pk->revkey && pk->numrevkeys )
BUG();
else
for(i=0;inumrevkeys;i++)
{
/* The revoker's keyid. */
u32 keyid[2];
keyid_from_fingerprint (ctrl, pk->revkey[i].fpr,
MAX_FINGERPRINT_LEN, keyid);
if(keyid[0]==sig->keyid[0] && keyid[1]==sig->keyid[1])
/* The signature was generated by a designated revoker.
Verify the signature. */
{
gcry_md_hd_t md;
if (gcry_md_open (&md, sig->digest_algo, 0))
BUG ();
hash_public_key(md,pk);
/* Note: check_signature only checks that the signature
is good. It does not fail if the key is revoked. */
rc = check_signature (ctrl, sig, md);
cache_sig_result(sig,rc);
gcry_md_close (md);
break;
}
}
busy=0;
return rc;
}
/* Check that the backsig BACKSIG from the subkey SUB_PK to its
- primary key MAIN_PK is valid.
-
- Backsigs (0x19) have the same format as binding sigs (0x18), but
- this function is simpler than check_key_signature in a few ways.
- For example, there is no support for expiring backsigs since it is
- questionable what such a thing actually means. Note also that the
- sig cache check here, unlike other sig caches in GnuPG, is not
- persistent. */
+ * primary key MAIN_PK is valid.
+ *
+ * Backsigs (0x19) have the same format as binding sigs (0x18), but
+ * this function is simpler than check_key_signature in a few ways.
+ * For example, there is no support for expiring backsigs since it is
+ * questionable what such a thing actually means. Note also that the
+ * sig cache check here, unlike other sig caches in GnuPG, is not
+ * persistent. */
int
check_backsig (PKT_public_key *main_pk,PKT_public_key *sub_pk,
PKT_signature *backsig)
{
gcry_md_hd_t md;
int rc;
/* Always check whether the algorithm is available. Although
gcry_md_open would throw an error, some libgcrypt versions will
print a debug message in that case too. */
if ((rc=openpgp_md_test_algo (backsig->digest_algo)))
return rc;
if(!opt.no_sig_cache && backsig->flags.checked)
return backsig->flags.valid? 0 : gpg_error (GPG_ERR_BAD_SIGNATURE);
rc = gcry_md_open (&md, backsig->digest_algo,0);
if (!rc)
{
hash_public_key(md,main_pk);
hash_public_key(md,sub_pk);
rc = check_signature_end (sub_pk, backsig, md, NULL, NULL, NULL);
cache_sig_result(backsig,rc);
gcry_md_close(md);
}
return rc;
}
/* Check that a signature over a key is valid. This is a
* specialization of check_key_signature2 with the unnamed parameters
* passed as NULL. See the documentation for that function for more
* details. */
int
check_key_signature (ctrl_t ctrl, kbnode_t root, kbnode_t node,
int *is_selfsig)
{
return check_key_signature2 (ctrl, root, node, NULL, NULL,
is_selfsig, NULL, NULL);
}
/* Returns whether SIGNER generated the signature SIG over the packet
* PACKET, which is a key, subkey or uid, and comes from the key block
* KB. (KB is PACKET's corresponding keyblock; we don't assume that
* SIG has been added to the keyblock.)
*
* If SIGNER is set, then checks whether SIGNER generated the
* signature. Otherwise, uses SIG->KEYID to find the alleged signer.
* This parameter can be used to effectively override the alleged
* signer that is stored in SIG.
*
* KB may be NULL if SIGNER is set.
*
* Unlike check_key_signature, this function ignores any cached
* results! That is, it does not consider SIG->FLAGS.CHECKED and
* SIG->FLAGS.VALID nor does it set them.
*
* This doesn't check the signature's semantic mean. Concretely, it
* doesn't check whether a non-self signed revocation signature was
* created by a designated revoker. In fact, it doesn't return an
* error for a binding generated by a completely different key!
*
* Returns 0 if the signature is valid. Returns GPG_ERR_SIG_CLASS if
* this signature can't be over PACKET. Returns GPG_ERR_NOT_FOUND if
* the key that generated the signature (according to SIG) could not
* be found. Returns GPG_ERR_BAD_SIGNATURE if the signature is bad.
* Other errors codes may be returned if something else goes wrong.
*
* IF IS_SELFSIG is not NULL, sets *IS_SELFSIG to 1 if this is a
* self-signature (by the key's primary key) or 0 if not.
*
* If RET_PK is not NULL, returns a copy of the public key that
* generated the signature (i.e., the signer) on success. This must
* be released by the caller using release_public_key_parts (). */
gpg_error_t
check_signature_over_key_or_uid (ctrl_t ctrl, PKT_public_key *signer,
PKT_signature *sig, KBNODE kb, PACKET *packet,
int *is_selfsig, PKT_public_key *ret_pk)
{
int rc;
PKT_public_key *pripk = kb->pkt->pkt.public_key;
gcry_md_hd_t md;
int signer_alloced = 0;
rc = openpgp_pk_test_algo (sig->pubkey_algo);
if (rc)
return rc;
rc = openpgp_md_test_algo (sig->digest_algo);
if (rc)
return rc;
/* A signature's class indicates the type of packet that it
signs. */
- if (/* Primary key binding (made by a subkey). */
- sig->sig_class == 0x19
- /* Direct key signature. */
- || sig->sig_class == 0x1f
- /* Primary key revocation. */
- || sig->sig_class == 0x20)
+ if (IS_BACK_SIG (sig) || IS_KEY_SIG (sig) || IS_KEY_REV (sig))
{
/* Key revocations can only be over primary keys. */
if (packet->pkttype != PKT_PUBLIC_KEY)
return gpg_error (GPG_ERR_SIG_CLASS);
}
- else if (/* Subkey binding. */
- sig->sig_class == 0x18
- /* Subkey revocation. */
- || sig->sig_class == 0x28)
+ else if (IS_SUBKEY_SIG (sig) || IS_SUBKEY_REV (sig))
{
if (packet->pkttype != PKT_PUBLIC_SUBKEY)
return gpg_error (GPG_ERR_SIG_CLASS);
}
- else if (/* Certification. */
- sig->sig_class == 0x10
- || sig->sig_class == 0x11
- || sig->sig_class == 0x12
- || sig->sig_class == 0x13
- /* Certification revocation. */
- || sig->sig_class == 0x30)
+ else if (IS_UID_SIG (sig) || IS_UID_REV (sig))
{
if (packet->pkttype != PKT_USER_ID)
return gpg_error (GPG_ERR_SIG_CLASS);
}
else
return gpg_error (GPG_ERR_SIG_CLASS);
/* PACKET is the right type for SIG. */
if (signer)
{
if (is_selfsig)
{
if (signer->keyid[0] == pripk->keyid[0]
&& signer->keyid[1] == pripk->keyid[1])
*is_selfsig = 1;
else
*is_selfsig = 0;
}
}
else
{
/* Get the signer. If possible, avoid a look up. */
if (sig->keyid[0] == pripk->keyid[0]
&& sig->keyid[1] == pripk->keyid[1])
{
/* Issued by the primary key. */
signer = pripk;
if (is_selfsig)
*is_selfsig = 1;
}
else
{
/* See if one of the subkeys was the signer (although this
- is extremely unlikely). */
+ * is extremely unlikely). */
kbnode_t ctx = NULL;
kbnode_t n;
while ((n = walk_kbnode (kb, &ctx, 0)))
{
PKT_public_key *subk;
if (n->pkt->pkttype != PKT_PUBLIC_SUBKEY)
continue;
subk = n->pkt->pkt.public_key;
if (sig->keyid[0] == subk->keyid[0]
&& sig->keyid[1] == subk->keyid[1])
{
/* Issued by a subkey. */
signer = subk;
break;
}
}
if (! signer)
{
/* Signer by some other key. */
if (is_selfsig)
*is_selfsig = 0;
if (ret_pk)
{
signer = ret_pk;
/* FIXME: Using memset here is probematic because it
* assumes that there are no allocated fields in
* SIGNER. */
memset (signer, 0, sizeof (*signer));
signer_alloced = 1;
}
else
{
signer = xmalloc_clear (sizeof (*signer));
signer_alloced = 2;
}
rc = get_pubkey (ctrl, signer, sig->keyid);
if (rc)
{
xfree (signer);
signer = NULL;
signer_alloced = 0;
goto leave;
}
}
}
}
/* We checked above that we supported this algo, so an error here is
* a bug. */
if (gcry_md_open (&md, sig->digest_algo, 0))
BUG ();
/* Hash the relevant data. */
- if (/* Direct key signature. */
- sig->sig_class == 0x1f
- /* Primary key revocation. */
- || sig->sig_class == 0x20)
+ if (IS_KEY_SIG (sig) || IS_KEY_REV (sig))
{
log_assert (packet->pkttype == PKT_PUBLIC_KEY);
hash_public_key (md, packet->pkt.public_key);
rc = check_signature_end_simple (signer, sig, md);
}
- else if (/* Primary key binding (made by a subkey). */
- sig->sig_class == 0x19)
+ else if (IS_BACK_SIG (sig))
{
log_assert (packet->pkttype == PKT_PUBLIC_KEY);
hash_public_key (md, packet->pkt.public_key);
hash_public_key (md, signer);
rc = check_signature_end_simple (signer, sig, md);
}
- else if (/* Subkey binding. */
- sig->sig_class == 0x18
- /* Subkey revocation. */
- || sig->sig_class == 0x28)
+ else if (IS_SUBKEY_SIG (sig) || IS_SUBKEY_REV (sig))
{
log_assert (packet->pkttype == PKT_PUBLIC_SUBKEY);
hash_public_key (md, pripk);
hash_public_key (md, packet->pkt.public_key);
rc = check_signature_end_simple (signer, sig, md);
}
- else if (/* Certification. */
- sig->sig_class == 0x10
- || sig->sig_class == 0x11
- || sig->sig_class == 0x12
- || sig->sig_class == 0x13
- /* Certification revocation. */
- || sig->sig_class == 0x30)
+ else if (IS_UID_SIG (sig) || IS_UID_REV (sig))
{
log_assert (packet->pkttype == PKT_USER_ID);
hash_public_key (md, pripk);
hash_uid_packet (packet->pkt.user_id, md, sig);
rc = check_signature_end_simple (signer, sig, md);
}
else
{
/* We should never get here. (The first if above should have
* already caught this error.) */
BUG ();
}
gcry_md_close (md);
leave:
if (! rc && ret_pk && ret_pk != signer)
copy_public_key (ret_pk, signer);
if (signer_alloced)
{
/* We looked up SIGNER; it is not a pointer into KB. */
release_public_key_parts (signer);
/* Free if we also allocated the memory. */
if (signer_alloced == 2)
xfree (signer);
}
return rc;
}
/* Check that a signature over a key (e.g., a key revocation, key
* binding, user id certification, etc.) is valid. If the function
* detects a self-signature, it uses the public key from the specified
* key block and does not bother looking up the key specified in the
* signature packet.
*
* ROOT is a keyblock.
*
* NODE references a signature packet that appears in the keyblock
* that should be verified.
*
* If CHECK_PK is set, the specified key is sometimes preferred for
* verifying signatures. See the implementation for details.
*
* If RET_PK is not NULL, the public key that successfully verified
* the signature is copied into *RET_PK.
*
* If IS_SELFSIG is not NULL, *IS_SELFSIG is set to 1 if NODE is a
* self-signature.
*
* If R_EXPIREDATE is not NULL, *R_EXPIREDATE is set to the expiry
* date.
*
* If R_EXPIRED is not NULL, *R_EXPIRED is set to 1 if PK has been
* expired (0 otherwise). Note: PK being revoked does not cause this
* function to fail.
*
*
* If OPT.NO_SIG_CACHE is not set, this function will first check if
* the result of a previous verification is already cached in the
* signature packet's data structure.
*
* TODO: add r_revoked here as well. It has the same problems as
* r_expiredate and r_expired and the cache. */
int
check_key_signature2 (ctrl_t ctrl,
kbnode_t root, kbnode_t node, PKT_public_key *check_pk,
PKT_public_key *ret_pk, int *is_selfsig,
u32 *r_expiredate, int *r_expired )
{
PKT_public_key *pk;
PKT_signature *sig;
int algo;
int rc;
if (is_selfsig)
*is_selfsig = 0;
if (r_expiredate)
*r_expiredate = 0;
if (r_expired)
*r_expired = 0;
log_assert (node->pkt->pkttype == PKT_SIGNATURE);
log_assert (root->pkt->pkttype == PKT_PUBLIC_KEY);
pk = root->pkt->pkt.public_key;
sig = node->pkt->pkt.signature;
algo = sig->digest_algo;
/* Check whether we have cached the result of a previous signature
* check. Note that we may no longer have the pubkey or hash
* needed to verify a sig, but can still use the cached value. A
* cache refresh detects and clears these cases. */
if ( !opt.no_sig_cache )
{
cache_stats.total++;
if (sig->flags.checked) /* Cached status available. */
{
cache_stats.cached++;
if (is_selfsig)
{
u32 keyid[2];
keyid_from_pk (pk, keyid);
if (keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1])
*is_selfsig = 1;
}
/* BUG: This is wrong for non-self-sigs... needs to be the
* actual pk. */
rc = check_signature_metadata_validity (pk, sig, r_expired, NULL);
if (rc)
return rc;
if (sig->flags.valid)
{
cache_stats.goodsig++;
return 0;
}
cache_stats.badsig++;
return gpg_error (GPG_ERR_BAD_SIGNATURE);
}
}
rc = openpgp_pk_test_algo(sig->pubkey_algo);
if (rc)
return rc;
rc = openpgp_md_test_algo(algo);
if (rc)
return rc;
- if (sig->sig_class == 0x20) /* key revocation */
+ if (IS_KEY_REV (sig))
{
u32 keyid[2];
keyid_from_pk( pk, keyid );
/* Is it a designated revoker? */
if (keyid[0] != sig->keyid[0] || keyid[1] != sig->keyid[1])
rc = check_revocation_keys (ctrl, pk, sig);
else
{
rc = check_signature_metadata_validity (pk, sig,
r_expired, NULL);
if (! rc)
rc = check_signature_over_key_or_uid (ctrl, pk, sig,
root, root->pkt,
is_selfsig, ret_pk);
}
}
- else if (sig->sig_class == 0x28 /* subkey revocation */
- || sig->sig_class == 0x18) /* key binding */
+ else if (IS_SUBKEY_REV (sig) || IS_SUBKEY_SIG (sig))
{
kbnode_t snode = find_prev_kbnode (root, node, PKT_PUBLIC_SUBKEY);
if (snode)
{
rc = check_signature_metadata_validity (pk, sig,
r_expired, NULL);
if (! rc)
{
- /* 0x28 must be a self-sig, but 0x18 needn't be. */
+ /* A subkey revocation (0x28) must be a self-sig, but a
+ * subkey signature (0x18) needn't be. */
rc = check_signature_over_key_or_uid (ctrl,
- sig->sig_class == 0x18
+ IS_SUBKEY_SIG (sig)
? NULL : pk,
sig, root, snode->pkt,
is_selfsig, ret_pk);
}
}
else
{
if (opt.verbose)
{
- if (sig->sig_class == 0x28)
+ if (IS_SUBKEY_REV (sig))
log_info (_("key %s: no subkey for subkey"
" revocation signature\n"), keystr_from_pk(pk));
else if (sig->sig_class == 0x18)
log_info(_("key %s: no subkey for subkey"
" binding signature\n"), keystr_from_pk(pk));
}
rc = GPG_ERR_SIG_CLASS;
}
}
- else if (sig->sig_class == 0x1f) /* direct key signature */
+ else if (IS_KEY_SIG (sig)) /* direct key signature */
{
rc = check_signature_metadata_validity (pk, sig,
r_expired, NULL);
if (! rc)
rc = check_signature_over_key_or_uid (ctrl, pk, sig, root, root->pkt,
is_selfsig, ret_pk);
}
- else if (/* Certification. */
- sig->sig_class == 0x10
- || sig->sig_class == 0x11
- || sig->sig_class == 0x12
- || sig->sig_class == 0x13
- /* Certification revocation. */
- || sig->sig_class == 0x30)
+ else if (IS_UID_SIG (sig) || IS_UID_REV (sig))
{
kbnode_t unode = find_prev_kbnode (root, node, PKT_USER_ID);
if (unode)
{
rc = check_signature_metadata_validity (pk, sig, r_expired, NULL);
if (! rc)
{
/* If this is a self-sig, ignore check_pk. */
rc = check_signature_over_key_or_uid
(ctrl,
keyid_cmp (pk_keyid (pk), sig->keyid) == 0 ? pk : check_pk,
sig, root, unode->pkt, NULL, ret_pk);
}
}
else
{
if (!opt.quiet)
log_info ("key %s: no user ID for key signature packet"
" of class %02x\n",keystr_from_pk(pk),sig->sig_class);
rc = GPG_ERR_SIG_CLASS;
}
}
else
{
log_info ("sig issued by %s with class %d (digest: %02x %02x)"
" is not valid over a user id or a key id, ignoring.\n",
keystr (sig->keyid), sig->sig_class,
sig->digest_start[0], sig->digest_start[1]);
rc = gpg_error (GPG_ERR_BAD_SIGNATURE);
}
cache_sig_result (sig, rc);
return rc;
}