diff --git a/g10/sig-check.c b/g10/sig-check.c index 75b06e858..bcf46f8b4 100644 --- a/g10/sig-check.c +++ b/g10/sig-check.c @@ -48,42 +48,43 @@ check_signature (PKT_signature *sig, gcry_md_hd_t digest) return check_signature2 (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 PK is not NULL, the public key is saved in *PK on success. - - Returns 0 on success. An error code otherwise. */ + * + * 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 PK is not NULL, the public key is saved in *PK on success. + * + * Returns 0 on success. An error code otherwise. */ int check_signature2 (PKT_signature *sig, gcry_md_hd_t digest, u32 *r_expiredate, int *r_expired, int *r_revoked, PKT_public_key *pk ) @@ -237,22 +238,22 @@ check_signature2 (PKT_signature *sig, gcry_md_hd_t digest, u32 *r_expiredate, /* 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.) */ + * 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) @@ -318,34 +319,34 @@ check_signature_metadata_validity (PKT_public_key *pk, PKT_signature *sig, /* 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. */ + * 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, @@ -486,35 +487,36 @@ cache_sig_result ( PKT_signature *sig, int result ) } } + /* 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 */ + * 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 (PKT_public_key *pk, PKT_signature *sig) { @@ -526,29 +528,29 @@ check_revocation_keys (PKT_public_key *pk, PKT_signature *sig) 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. */ + * + * - 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 @@ -637,202 +639,225 @@ check_backsig (PKT_public_key *main_pk,PKT_public_key *sub_pk, /* 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. */ + * 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 (KBNODE root, KBNODE node, int *is_selfsig) { return check_key_signature2 (root, node, NULL, NULL, is_selfsig, NULL, NULL); } + /* 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. */ + * 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(KBNODE root, KBNODE node, PKT_public_key *check_pk, - PKT_public_key *ret_pk, int *is_selfsig, - u32 *r_expiredate, int *r_expired ) +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; - int rc; + gcry_md_hd_t md; + 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; - assert( node->pkt->pkttype == PKT_SIGNATURE ); - assert( root->pkt->pkttype == PKT_PUBLIC_KEY ); + if (is_selfsig) + *is_selfsig = 0; + if (r_expiredate) + *r_expiredate = 0; + if (r_expired) + *r_expired = 0; + assert (node->pkt->pkttype == PKT_SIGNATURE); + assert (root->pkt->pkttype == PKT_PUBLIC_KEY); - pk = root->pkt->pkt.public_key; - sig = node->pkt->pkt.signature; - algo = sig->digest_algo; + 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 ) { - if (sig->flags.checked) { /*cached status available*/ - if( is_selfsig ) { - u32 keyid[2]; + /* 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 ) + { + if (sig->flags.checked) /* Cached status available. */ + { + 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; + 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 */ - if((rc = check_signature_metadata_validity (pk, sig, - r_expired, NULL))) - return rc; - return sig->flags.valid? 0 : gpg_error (GPG_ERR_BAD_SIGNATURE); + /* 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; + return sig->flags.valid? 0 : gpg_error (GPG_ERR_BAD_SIGNATURE); } } - if( (rc=openpgp_pk_test_algo(sig->pubkey_algo)) ) - return rc; - if( (rc=openpgp_md_test_algo(algo)) ) - return rc; + 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 */ - u32 keyid[2]; - keyid_from_pk( pk, keyid ); + if (sig->sig_class == 0x20) /* key revocation */ + { + 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(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); - } + /* Is it a designated revoker? */ + if (keyid[0] != sig->keyid[0] || keyid[1] != sig->keyid[1]) + 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); + } } - else if( sig->sig_class == 0x28 ) { /* subkey revocation */ - KBNODE snode = find_prev_kbnode( root, node, PKT_PUBLIC_SUBKEY ); + else if (sig->sig_class == 0x28) /* subkey revocation */ + { + 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); + 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); } - else - { - if (opt.verbose) - log_info (_("key %s: no subkey for subkey" - " revocation signature\n"),keystr_from_pk(pk)); - rc = GPG_ERR_SIG_CLASS; - } + else + { + if (opt.verbose) + log_info (_("key %s: no subkey for subkey" + " revocation signature\n"), keystr_from_pk(pk)); + rc = GPG_ERR_SIG_CLASS; + } } - else if( sig->sig_class == 0x18 ) { /* key binding */ - KBNODE snode = find_prev_kbnode( root, node, PKT_PUBLIC_SUBKEY ); + 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????? */ - u32 keyid[2]; /* it should always be a selfsig */ + 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; - } + 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 ); + 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); - } + gcry_md_close (md); + } else { if (opt.verbose) log_info(_("key %s: no subkey for subkey" - " binding signature\n"),keystr_from_pk(pk)); + " binding signature\n"), keystr_from_pk(pk)); rc = GPG_ERR_SIG_CLASS; } - } - else if( sig->sig_class == 0x1f ) { /* direct key signature */ + } + 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); - } - else { /* all other classes */ - KBNODE unode = find_prev_kbnode( root, node, PKT_USER_ID ); + cache_sig_result (sig, rc); + gcry_md_close (md); + } + else /* all other classes */ + { + kbnode_t unode = find_prev_kbnode (root, node, PKT_USER_ID); - if( unode ) { + if (unode) + { u32 keyid[2]; - keyid_from_pk( pk, keyid ); - if (gcry_md_open (&md, algo, 0 )) + 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 ) + 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. XXX: Could it be that the key is - not is not in this keyblock? */ - rc = check_signature2 (sig, md, r_expiredate, r_expired, - NULL, ret_pk); + { /* The caller specified a key. Try that. */ - cache_sig_result ( sig, rc ); - gcry_md_close(md); - } + 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); + } else { if (!opt.quiet) @@ -840,7 +865,7 @@ check_key_signature2(KBNODE root, KBNODE node, PKT_public_key *check_pk, " of class %02x\n",keystr_from_pk(pk),sig->sig_class); rc = GPG_ERR_SIG_CLASS; } - } + } - return rc; + return rc; }