1
0
mirror of git://git.gnupg.org/gnupg.git synced 2025-03-25 22:19:59 +01:00

gpg: Split check_key_signature2.

* g10/sig-check.c (hash_uid_node): Rename from this...
(hash_uid_packet): ... to this.  Take a PKT_user_id instead of a
KBNODE.
(check_key_signature2): Split the basic signature checking
functionality into...
(check_signature_over_key_or_uid): ... this new function.

--
Signed-off-by: Neal H. Walfield <neal@g10code.com>
This commit is contained in:
Neal H. Walfield 2016-02-19 15:30:03 +01:00
parent 5fbd80579a
commit 44cdb9d73f
2 changed files with 286 additions and 92 deletions

View File

@ -263,6 +263,19 @@ int check_key_signature2( KBNODE root, KBNODE node, PKT_public_key *check_pk,
PKT_public_key *ret_pk, int *is_selfsig,
u32 *r_expiredate, int *r_expired );
/* 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. If SIGNER is NULL, it is looked up based on the information in
SIG. If not NULL, sets *IS_SELFSIG to indicate whether the
signature is a self-signature and *RET_PK to a copy of the signer's
key. */
gpg_error_t check_signature_over_key_or_uid (PKT_public_key *signer,
PKT_signature *sig,
KBNODE kb, PACKET *packet,
int *is_selfsig,
PKT_public_key *ret_pk);
/*-- delkey.c --*/
gpg_error_t delete_keys (strlist_t names, int secret, int allow_both);

View File

@ -1,7 +1,7 @@
/* sig-check.c - Check a signature
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003,
* 2004, 2006 Free Software Foundation, Inc.
* Copyright (C) 2015 g10 Code GmbH
* Copyright (C) 2015, 2016 g10 Code GmbH
*
* This file is part of GnuPG.
*
@ -481,11 +481,8 @@ check_signature_end_simple (PKT_public_key *pk, PKT_signature *sig,
/* Add a uid node to a hash context. See section 5.2.4, paragraph 4
of RFC 4880. */
static void
hash_uid_node( KBNODE unode, gcry_md_hd_t md, PKT_signature *sig )
hash_uid_packet (PKT_user_id *uid, gcry_md_hd_t md, PKT_signature *sig )
{
PKT_user_id *uid = unode->pkt->pkt.user_id;
assert( unode->pkt->pkttype == PKT_USER_ID );
if( uid->attrib_data ) {
if( sig->version >=4 ) {
byte buf[5];
@ -691,6 +688,232 @@ check_key_signature (KBNODE root, KBNODE node, int *is_selfsig)
}
/* 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 (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 (packet->pkttype != PKT_PUBLIC_KEY)
/* Key revocations can only be over primary keys. */
return gpg_error (GPG_ERR_SIG_CLASS);
}
else if (/* Subkey binding. */
sig->sig_class == 0x18
/* Subkey revocation. */
|| sig->sig_class == 0x28)
{
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)
{
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). */
{
kbnode_t ctx = NULL;
kbnode_t n;
while ((n = walk_kbnode (kb, &ctx, PKT_PUBLIC_SUBKEY)))
{
PKT_public_key *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;
memset (signer, 0, sizeof (*signer));
signer_alloced = 1;
}
else
{
signer = xmalloc_clear (sizeof (*signer));
signer_alloced = 2;
}
rc = get_pubkey (signer, sig->keyid);
if (rc)
{
xfree (signer);
signer = NULL;
signer_alloced = 0;
goto out;
}
}
}
}
/* 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)
{
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)
{
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)
{
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)
{
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);
out:
if (! rc && ret_pk && (signer_alloced == -1 || ret_pk != signer))
copy_public_key (ret_pk, signer);
if (signer_alloced == 1)
/* We looked up SIGNER; it is not a pointer into KB. */
{
release_public_key_parts (signer);
if (signer_alloced == 2)
/* We also allocated the memory. */
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
@ -730,7 +953,6 @@ check_key_signature2 (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 )
{
gcry_md_hd_t md;
PKT_public_key *pk;
PKT_signature *sig;
int algo;
@ -791,114 +1013,69 @@ check_key_signature2 (kbnode_t root, kbnode_t node, PKT_public_key *check_pk,
rc = check_revocation_keys (pk, sig);
else
{
if (gcry_md_open (&md, algo, 0))
BUG ();
hash_public_key (md, pk);
rc = check_signature_end (pk, sig, md, r_expired, NULL, ret_pk);
cache_sig_result (sig, rc);
gcry_md_close (md);
rc = check_signature_metadata_validity (pk, sig,
r_expired, NULL);
if (! rc)
rc = check_signature_over_key_or_uid (pk, sig, root, root->pkt,
is_selfsig, ret_pk);
}
}
else if (sig->sig_class == 0x28) /* subkey revocation */
else if (sig->sig_class == 0x28 /* subkey revocation */
|| sig->sig_class == 0x18) /* key binding */
{
kbnode_t snode = find_prev_kbnode (root, node, PKT_PUBLIC_SUBKEY);
if (snode)
{
if (gcry_md_open (&md, algo, 0))
BUG ();
hash_public_key (md, pk);
hash_public_key (md, snode->pkt->pkt.public_key);
rc = check_signature_end (pk, sig, md, r_expired, NULL, ret_pk);
cache_sig_result (sig, rc);
gcry_md_close (md);
rc = check_signature_metadata_validity (pk, sig,
r_expired, NULL);
if (! rc)
/* 0x28 must be a self-sig, but 0x18 needn't be. */
rc = check_signature_over_key_or_uid (sig->sig_class == 0x18
? NULL : pk,
sig, root, snode->pkt,
is_selfsig, ret_pk);
}
else
{
if (opt.verbose)
log_info (_("key %s: no subkey for subkey"
" revocation signature\n"), keystr_from_pk(pk));
{
if (sig->sig_class == 0x28)
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 == 0x18) /* key binding */
{
kbnode_t snode = find_prev_kbnode (root, node, PKT_PUBLIC_SUBKEY);
if (snode)
{
if (is_selfsig)
{
/* Does this make sense? It should always be a
selfsig. Yes: We can't be sure about this and we
need to be able to indicate that it is a selfsig.
FIXME: The question is whether we should reject
such a signature if it is not a selfsig. */
u32 keyid[2];
keyid_from_pk (pk, keyid);
if (keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1])
*is_selfsig = 1;
}
if (gcry_md_open (&md, algo, 0))
BUG ();
hash_public_key (md, pk);
hash_public_key (md, snode->pkt->pkt.public_key);
rc = check_signature_end (pk, sig, md, r_expired, NULL, ret_pk);
cache_sig_result ( sig, rc );
gcry_md_close (md);
}
else
{
if (opt.verbose)
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 */
{
if (gcry_md_open (&md, algo, 0 ))
BUG ();
hash_public_key( md, pk );
rc = check_signature_end (pk, sig, md, r_expired, NULL, ret_pk);
cache_sig_result (sig, rc);
gcry_md_close (md);
rc = check_signature_metadata_validity (pk, sig,
r_expired, NULL);
if (! rc)
rc = check_signature_over_key_or_uid (pk, sig, root, root->pkt,
is_selfsig, ret_pk);
}
else /* all other classes */
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)
{
kbnode_t unode = find_prev_kbnode (root, node, PKT_USER_ID);
if (unode)
{
u32 keyid[2];
keyid_from_pk (pk, keyid);
if (gcry_md_open (&md, algo, 0))
BUG ();
hash_public_key (md, pk);
hash_uid_node (unode, md, sig);
if (keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1])
{ /* The primary key is the signing key. */
if (is_selfsig)
*is_selfsig = 1;
rc = check_signature_end (pk, sig, md, r_expired, NULL, ret_pk);
}
else if (check_pk)
{ /* The caller specified a key. Try that. */
rc = check_signature_end (check_pk, sig, md,
r_expired, NULL, ret_pk);
}
else
{ /* Look up the key. */
rc = check_signature2 (sig, md, r_expiredate, r_expired,
NULL, ret_pk);
}
cache_sig_result (sig, rc);
gcry_md_close (md);
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
(keyid_cmp (pk_keyid (pk), sig->keyid) == 0 ? pk : check_pk,
sig, root, unode->pkt, NULL, ret_pk);
}
else
{
@ -908,6 +1085,10 @@ check_key_signature2 (kbnode_t root, kbnode_t node, PKT_public_key *check_pk,
rc = GPG_ERR_SIG_CLASS;
}
}
else
BUG ();
cache_sig_result (sig, rc);
return rc;
}