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; }