1 /* sig-check.c - Check signatures
2 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2007, 2008, 2010
3 * Free Software Foundation, Inc.
7 * This file is part of OpenCDK.
9 * The OpenCDK library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 2.1 of
12 * the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
35 /* Hash all multi precision integers of the key PK with the given
36 message digest context MD. */
38 hash_mpibuf (cdk_pubkey_t pk, digest_hd_st * md, int usefpr)
40 byte buf[MAX_MPI_BYTES]; /* FIXME: do not use hardcoded length. */
45 /* We have to differ between two modes for v3 keys. To form the
46 fingerprint, we hash the MPI values without the length prefix.
47 But if we calculate the hash for verifying/signing we use all data. */
48 npkey = cdk_pk_get_npkey (pk->pubkey_algo);
49 for (i = 0; i < npkey; i++)
51 nbytes = MAX_MPI_BYTES;
52 err = _gnutls_mpi_print_pgp (pk->mpi[i], buf, &nbytes);
57 return map_gnutls_error (err);
60 if (!usefpr || pk->version == 4)
61 _gnutls_hash (md, buf, nbytes);
62 else /* without the prefix. */
63 _gnutls_hash (md, buf + 2, nbytes - 2);
69 /* Hash an entire public key PK with the given message digest context
70 MD. The @usefpr param is only valid for version 3 keys because of
71 the different way to calculate the fingerprint. */
73 _cdk_hash_pubkey (cdk_pubkey_t pk, digest_hd_st * md, int usefpr)
81 if (usefpr && pk->version < 4 && is_RSA (pk->pubkey_algo))
82 return hash_mpibuf (pk, md, 1);
84 /* The version 4 public key packet does not have the 2 octets for
85 the expiration date. */
86 n = pk->version < 4 ? 8 : 6;
87 npkey = cdk_pk_get_npkey (pk->pubkey_algo);
88 for (i = 0; i < npkey; i++)
89 n = n + (_gnutls_mpi_get_nbits (pk->mpi[i]) + 7) / 8 + 2;
95 buf[i++] = pk->version;
96 buf[i++] = pk->timestamp >> 24;
97 buf[i++] = pk->timestamp >> 16;
98 buf[i++] = pk->timestamp >> 8;
99 buf[i++] = pk->timestamp >> 0;
105 /* Convert the expiration date into days. */
107 a = (u16) ((pk->expiredate - pk->timestamp) / 86400L);
111 buf[i++] = pk->pubkey_algo;
112 _gnutls_hash (md, buf, i);
113 return hash_mpibuf (pk, md, 0);
117 /* Hash the user ID @uid with the given message digest @md.
118 Use openpgp mode if @is_v4 is 1. */
120 _cdk_hash_userid (cdk_pkt_userid_t uid, int is_v4, digest_hd_st * md)
127 return CDK_Inv_Value;
131 _gnutls_hash (md, (byte *) uid->name, uid->len);
135 dlen = uid->attrib_img ? uid->attrib_len : uid->len;
136 data = uid->attrib_img ? uid->attrib_img : (byte *) uid->name;
137 buf[0] = uid->attrib_img ? 0xD1 : 0xB4;
142 _gnutls_hash (md, buf, 5);
143 _gnutls_hash (md, data, dlen);
148 /* Hash all parts of the signature which are needed to derive
149 the correct message digest to verify the sig. */
151 _cdk_hash_sig_data (cdk_pkt_signature_t sig, digest_hd_st * md)
157 return CDK_Inv_Value;
159 if (sig->version == 4)
160 _gnutls_hash (md, &sig->version, 1);
162 _gnutls_hash (md, &sig->sig_class, 1);
163 if (sig->version < 4)
165 buf[0] = sig->timestamp >> 24;
166 buf[1] = sig->timestamp >> 16;
167 buf[2] = sig->timestamp >> 8;
168 buf[3] = sig->timestamp >> 0;
169 _gnutls_hash (md, buf, 4);
175 tmp = _cdk_pub_algo_to_pgp (sig->pubkey_algo);
176 _gnutls_hash (md, &tmp, 1);
177 tmp = _gnutls_hash_algo_to_pgp (sig->digest_algo);
178 _gnutls_hash (md, &tmp, 1);
179 if (sig->hashed != NULL)
181 byte *p = _cdk_subpkt_get_array (sig->hashed, 0, &n);
185 _gnutls_hash (md, buf, 2);
186 _gnutls_hash (md, p, n);
188 sig->hashed_size = n;
189 n = sig->hashed_size + 6;
194 _gnutls_hash (md, &tmp, 1);
195 _gnutls_hash (md, &tmp, 1);
198 _gnutls_hash (md, &sig->version, 1);
200 _gnutls_hash (md, &tmp, 1);
205 _gnutls_hash (md, buf, 4);
211 /* Cache the signature result and store it inside the sig. */
213 cache_sig_result (cdk_pkt_signature_t sig, int res)
215 sig->flags.checked = 0;
216 sig->flags.valid = 0;
219 sig->flags.checked = 1;
220 sig->flags.valid = 1;
222 else if (res == CDK_Bad_Sig)
224 sig->flags.checked = 1;
225 sig->flags.valid = 0;
230 /* Check the given signature @sig with the public key @pk.
231 Use the digest handle @digest. */
233 _cdk_sig_check (cdk_pubkey_t pk, cdk_pkt_signature_t sig,
234 digest_hd_st * digest, int *r_expired)
237 byte md[MAX_DIGEST_LEN];
238 time_t cur_time = (u32) gnutls_time (NULL);
240 if (!pk || !sig || !digest)
243 return CDK_Inv_Value;
246 if (sig->flags.checked)
247 return sig->flags.valid ? 0 : CDK_Bad_Sig;
248 if (!KEY_CAN_SIGN (pk->pubkey_algo))
250 if (pk->timestamp > sig->timestamp || pk->timestamp > cur_time)
251 return CDK_Time_Conflict;
253 if (r_expired && pk->expiredate
254 && (pk->expiredate + pk->timestamp) > cur_time)
257 _cdk_hash_sig_data (sig, digest);
258 _gnutls_hash_output (digest, md);
260 if (md[0] != sig->digest_start[0] || md[1] != sig->digest_start[1])
263 return CDK_Chksum_Error;
266 rc = cdk_pk_verify (pk, sig, md);
267 cache_sig_result (sig, rc);
272 /* Check the given key signature.
273 @knode is the key node and @snode the signature node. */
275 _cdk_pk_check_sig (cdk_keydb_hd_t keydb,
276 cdk_kbnode_t knode, cdk_kbnode_t snode, int *is_selfsig,
282 cdk_pkt_signature_t sig;
287 if (!knode || !snode)
290 return CDK_Inv_Value;
295 if ((knode->pkt->pkttype != CDK_PKT_PUBLIC_KEY &&
296 knode->pkt->pkttype != CDK_PKT_PUBLIC_SUBKEY) ||
297 snode->pkt->pkttype != CDK_PKT_SIGNATURE)
300 return CDK_Inv_Value;
302 pk = knode->pkt->pkt.public_key;
303 sig = snode->pkt->pkt.signature;
305 err = _gnutls_hash_init (&md, sig->digest_algo);
309 return map_gnutls_error (err);
313 if (sig->sig_class == 0x20)
314 { /* key revocation */
315 cdk_kbnode_hash (knode, &md, 0, 0, 0);
316 rc = _cdk_sig_check (pk, sig, &md, &is_expired);
318 else if (sig->sig_class == 0x28)
319 { /* subkey revocation */
320 node = cdk_kbnode_find_prev (knode, snode, CDK_PKT_PUBLIC_SUBKEY);
322 { /* no subkey for subkey revocation packet */
324 rc = CDK_Error_No_Key;
327 cdk_kbnode_hash (knode, &md, 0, 0, 0);
328 cdk_kbnode_hash (node, &md, 0, 0, 0);
329 rc = _cdk_sig_check (pk, sig, &md, &is_expired);
331 else if (sig->sig_class == 0x18 || sig->sig_class == 0x19)
332 { /* primary/secondary key binding */
333 node = cdk_kbnode_find_prev (knode, snode, CDK_PKT_PUBLIC_SUBKEY);
335 { /* no subkey for subkey binding packet */
337 rc = CDK_Error_No_Key;
340 cdk_kbnode_hash (knode, &md, 0, 0, 0);
341 cdk_kbnode_hash (node, &md, 0, 0, 0);
342 rc = _cdk_sig_check (pk, sig, &md, &is_expired);
344 else if (sig->sig_class == 0x1F)
345 { /* direct key signature */
346 cdk_kbnode_hash (knode, &md, 0, 0, 0);
347 rc = _cdk_sig_check (pk, sig, &md, &is_expired);
350 { /* all other classes */
351 cdk_pkt_userid_t uid;
352 node = cdk_kbnode_find_prev (knode, snode, CDK_PKT_USER_ID);
354 { /* no user ID for key signature packet */
356 rc = CDK_Error_No_Key;
360 uid = node->pkt->pkt.user_id;
363 *ret_uid = uid->name;
365 cdk_kbnode_hash (knode, &md, 0, 0, 0);
366 cdk_kbnode_hash (node, &md, sig->version == 4, 0, 0);
368 if (pk->keyid[0] == sig->keyid[0] && pk->keyid[1] == sig->keyid[1])
370 rc = _cdk_sig_check (pk, sig, &md, &is_expired);
374 else if (keydb != NULL)
377 rc = cdk_keydb_get_pk (keydb, sig->keyid, &sig_pk);
379 rc = _cdk_sig_check (sig_pk, sig, &md, &is_expired);
380 cdk_pk_release (sig_pk);
384 _gnutls_hash_deinit (&md, NULL);
392 struct verify_uid *next;
396 uid_list_add_sig (struct verify_uid **list, const char *uid,
401 *list = cdk_calloc (1, sizeof (struct verify_uid));
403 return CDK_Out_Of_Core;
411 struct verify_uid *p, *prev_p = NULL;
418 if (strcmp (uid, p->name) == 0)
428 { /* not found add to the last */
429 prev_p->next = cdk_calloc (1, sizeof (struct verify_uid));
430 if (prev_p->next == NULL)
431 return CDK_Out_Of_Core;
432 prev_p->next->name = uid;
434 prev_p->next->nsigs++;
437 { /* found... increase sigs */
447 uid_list_free (struct verify_uid *list)
449 struct verify_uid *p, *p1;
460 /* returns non zero if all UIDs in the list have at least one
461 * signature. If the list is empty or no signatures are present
462 * a zero value is returned.
465 uid_list_all_signed (struct verify_uid *list)
467 struct verify_uid *p;
481 return 1; /* all signed */
486 * @key: the public key
487 * @hd: an optinal key database handle
488 * @r_status: variable to store the status of the key
490 * Check all signatures. When no key is available for checking, the
491 * sigstat is marked as 'NOKEY'. The @r_status contains the key flags
492 * which are or-ed or zero when there are no flags.
495 cdk_pk_check_sigs (cdk_kbnode_t key, cdk_keydb_hd_t keydb, int *r_status)
497 cdk_pkt_signature_t sig;
501 int key_status, is_selfsig = 0;
502 struct verify_uid *uid_list = NULL;
505 if (!key || !r_status)
508 return CDK_Inv_Value;
512 node = cdk_kbnode_find (key, CDK_PKT_PUBLIC_KEY);
516 return CDK_Error_No_Key;
520 /* Continue with the signature check but adjust the
521 key status flags accordingly. */
522 if (node->pkt->pkt.public_key->is_revoked)
523 key_status |= CDK_KEY_REVOKED;
524 if (node->pkt->pkt.public_key->has_expired)
525 key_status |= CDK_KEY_EXPIRED;
528 keyid = cdk_pk_get_keyid (node->pkt->pkt.public_key, NULL);
529 for (node = key; node; node = node->next)
531 if (node->pkt->pkttype != CDK_PKT_SIGNATURE)
533 sig = node->pkt->pkt.signature;
534 rc = _cdk_pk_check_sig (keydb, key, node, &is_selfsig, &uid_name);
536 if (rc && rc != CDK_Error_No_Key)
538 /* It might be possible that a single signature has been
539 corrupted, thus we do not consider it a problem when
540 one ore more signatures are bad. But at least the self
541 signature has to be valid. */
544 key_status |= CDK_KEY_INVALID;
549 _cdk_log_debug ("signature %s: signer %08X keyid %08X\n",
550 rc == CDK_Bad_Sig ? "BAD" : "good",
551 (unsigned int) sig->keyid[1], (unsigned int) keyid);
553 if (IS_UID_SIG (sig) && uid_name != NULL)
555 /* add every uid in the uid list. Only consider valid:
556 * - verification was ok
560 uid_list_add_sig (&uid_list, uid_name,
561 (rc == CDK_Success && is_selfsig == 0) ? 1 : 0);
562 if (rc != CDK_Success)
571 if (uid_list_all_signed (uid_list) == 0)
572 key_status |= CDK_KEY_NOSIGNER;
573 *r_status = key_status;
574 if (rc == CDK_Error_No_Key)
578 uid_list_free (uid_list);
584 * cdk_pk_check_self_sig:
586 * @r_status: output the status of the key.
588 * A convenient function to make sure the key is valid.
589 * Valid means the self signature is ok.
592 cdk_pk_check_self_sig (cdk_kbnode_t key, int *r_status)
594 cdk_pkt_signature_t sig;
597 u32 keyid[2], sigid[2];
598 int is_selfsig, sig_ok;
599 cdk_kbnode_t p, ctx = NULL;
602 if (!key || !r_status)
603 return CDK_Inv_Value;
605 cdk_pk_get_keyid (key->pkt->pkt.public_key, keyid);
607 while ((p = cdk_kbnode_walk (key, &ctx, 0)))
609 pkt = cdk_kbnode_get_packet (p);
610 if (pkt->pkttype != CDK_PKT_PUBLIC_SUBKEY
611 && pkt->pkttype != CDK_PKT_PUBLIC_KEY)
614 /* FIXME: we should set expire/revoke here also but callers
615 expect CDK_KEY_VALID=0 if the key is okay. */
617 for (node = p; node; node = node->next)
619 if (node->pkt->pkttype != CDK_PKT_SIGNATURE)
621 sig = node->pkt->pkt.signature;
623 cdk_sig_get_keyid (sig, sigid);
624 if (sigid[0] != keyid[0] || sigid[1] != keyid[1])
626 /* FIXME: Now we check all self signatures. */
627 rc = _cdk_pk_check_sig (NULL, p, node, &is_selfsig, NULL);
630 *r_status = CDK_KEY_INVALID;
633 else /* For each valid self sig we increase this counter. */
637 /* A key without a self signature is not valid. At least one
638 * signature for the given key has to be found.
642 *r_status = CDK_KEY_INVALID;
643 return CDK_General_Error;
647 /* No flags indicate a valid key. */
648 *r_status = CDK_KEY_VALID;