Made error code consistent with the other text parsing functions.
[gnutls.git] / lib / opencdk / sig-check.c
blob15d4c06f0b5a9b4d2ecdc4552782651954838134
1 /* sig-check.c - Check signatures
2 * Copyright (C) 1998-2012 Free Software Foundation, Inc.
4 * Author: Timo Schulz
6 * This file is part of OpenCDK.
8 * The OpenCDK library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; either version 3 of
11 * the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 #include <stdio.h>
27 #include <assert.h>
29 #include "opencdk.h"
30 #include "main.h"
31 #include "packet.h"
33 /* Hash all multi precision integers of the key PK with the given
34 message digest context MD. */
35 static int
36 hash_mpibuf (cdk_pubkey_t pk, digest_hd_st * md, int usefpr)
38 byte buf[MAX_MPI_BYTES]; /* FIXME: do not use hardcoded length. */
39 size_t nbytes;
40 size_t i, npkey;
41 int err;
43 /* We have to differ between two modes for v3 keys. To form the
44 fingerprint, we hash the MPI values without the length prefix.
45 But if we calculate the hash for verifying/signing we use all data. */
46 npkey = cdk_pk_get_npkey (pk->pubkey_algo);
47 for (i = 0; i < npkey; i++)
49 nbytes = MAX_MPI_BYTES;
50 err = _gnutls_mpi_print_pgp (pk->mpi[i], buf, &nbytes);
52 if (err < 0)
54 gnutls_assert ();
55 return map_gnutls_error (err);
58 if (!usefpr || pk->version == 4)
59 _gnutls_hash (md, buf, nbytes);
60 else /* without the prefix. */
61 _gnutls_hash (md, buf + 2, nbytes - 2);
63 return 0;
67 /* Hash an entire public key PK with the given message digest context
68 MD. The @usefpr param is only valid for version 3 keys because of
69 the different way to calculate the fingerprint. */
70 cdk_error_t
71 _cdk_hash_pubkey (cdk_pubkey_t pk, digest_hd_st * md, int usefpr)
73 byte buf[12];
74 size_t i, n, npkey;
76 if (!pk || !md)
77 return CDK_Inv_Value;
79 if (usefpr && pk->version < 4 && is_RSA (pk->pubkey_algo))
80 return hash_mpibuf (pk, md, 1);
82 /* The version 4 public key packet does not have the 2 octets for
83 the expiration date. */
84 n = pk->version < 4 ? 8 : 6;
85 npkey = cdk_pk_get_npkey (pk->pubkey_algo);
86 for (i = 0; i < npkey; i++)
87 n = n + (_gnutls_mpi_get_nbits (pk->mpi[i]) + 7) / 8 + 2;
89 i = 0;
90 buf[i++] = 0x99;
91 buf[i++] = n >> 8;
92 buf[i++] = n >> 0;
93 buf[i++] = pk->version;
94 buf[i++] = pk->timestamp >> 24;
95 buf[i++] = pk->timestamp >> 16;
96 buf[i++] = pk->timestamp >> 8;
97 buf[i++] = pk->timestamp >> 0;
99 if (pk->version < 4)
101 u16 a = 0;
103 /* Convert the expiration date into days. */
104 if (pk->expiredate)
105 a = (u16) ((pk->expiredate - pk->timestamp) / 86400L);
106 buf[i++] = a >> 8;
107 buf[i++] = a;
109 buf[i++] = pk->pubkey_algo;
110 _gnutls_hash (md, buf, i);
111 return hash_mpibuf (pk, md, 0);
115 /* Hash the user ID @uid with the given message digest @md.
116 Use openpgp mode if @is_v4 is 1. */
117 cdk_error_t
118 _cdk_hash_userid (cdk_pkt_userid_t uid, int is_v4, digest_hd_st * md)
120 const byte *data;
121 byte buf[5];
122 u32 dlen;
124 if (!uid || !md)
125 return CDK_Inv_Value;
127 if (!is_v4)
129 _gnutls_hash (md, (byte *) uid->name, uid->len);
130 return 0;
133 dlen = uid->attrib_img ? uid->attrib_len : uid->len;
134 data = uid->attrib_img ? uid->attrib_img : (byte *) uid->name;
135 buf[0] = uid->attrib_img ? 0xD1 : 0xB4;
136 buf[1] = dlen >> 24;
137 buf[2] = dlen >> 16;
138 buf[3] = dlen >> 8;
139 buf[4] = dlen >> 0;
140 _gnutls_hash (md, buf, 5);
141 _gnutls_hash (md, data, dlen);
142 return 0;
146 /* Hash all parts of the signature which are needed to derive
147 the correct message digest to verify the sig. */
148 cdk_error_t
149 _cdk_hash_sig_data (cdk_pkt_signature_t sig, digest_hd_st * md)
151 byte buf[4];
152 byte tmp;
154 if (!sig || !md)
155 return CDK_Inv_Value;
157 if (sig->version == 4)
158 _gnutls_hash (md, &sig->version, 1);
160 _gnutls_hash (md, &sig->sig_class, 1);
161 if (sig->version < 4)
163 buf[0] = sig->timestamp >> 24;
164 buf[1] = sig->timestamp >> 16;
165 buf[2] = sig->timestamp >> 8;
166 buf[3] = sig->timestamp >> 0;
167 _gnutls_hash (md, buf, 4);
169 else
171 size_t n;
173 tmp = _cdk_pub_algo_to_pgp (sig->pubkey_algo);
174 _gnutls_hash (md, &tmp, 1);
175 tmp = _gnutls_hash_algo_to_pgp (sig->digest_algo);
176 _gnutls_hash (md, &tmp, 1);
177 if (sig->hashed != NULL)
179 byte *p = _cdk_subpkt_get_array (sig->hashed, 0, &n);
180 assert (p != NULL);
181 buf[0] = n >> 8;
182 buf[1] = n >> 0;
183 _gnutls_hash (md, buf, 2);
184 _gnutls_hash (md, p, n);
185 cdk_free (p);
186 sig->hashed_size = n;
187 n = sig->hashed_size + 6;
189 else
191 tmp = 0x00;
192 _gnutls_hash (md, &tmp, 1);
193 _gnutls_hash (md, &tmp, 1);
194 n = 6;
196 _gnutls_hash (md, &sig->version, 1);
197 tmp = 0xff;
198 _gnutls_hash (md, &tmp, 1);
199 buf[0] = n >> 24;
200 buf[1] = n >> 16;
201 buf[2] = n >> 8;
202 buf[3] = n >> 0;
203 _gnutls_hash (md, buf, 4);
205 return 0;
209 /* Cache the signature result and store it inside the sig. */
210 static void
211 cache_sig_result (cdk_pkt_signature_t sig, int res)
213 sig->flags.checked = 0;
214 sig->flags.valid = 0;
215 if (res == 0)
217 sig->flags.checked = 1;
218 sig->flags.valid = 1;
220 else if (res == CDK_Bad_Sig)
222 sig->flags.checked = 1;
223 sig->flags.valid = 0;
228 /* Check the given signature @sig with the public key @pk.
229 Use the digest handle @digest. */
230 cdk_error_t
231 _cdk_sig_check (cdk_pubkey_t pk, cdk_pkt_signature_t sig,
232 digest_hd_st * digest, int *r_expired)
234 cdk_error_t rc;
235 byte md[MAX_DIGEST_LEN];
236 time_t cur_time = (u32) gnutls_time (NULL);
238 if (!pk || !sig || !digest)
240 gnutls_assert ();
241 return CDK_Inv_Value;
244 if (sig->flags.checked)
245 return sig->flags.valid ? 0 : CDK_Bad_Sig;
246 if (!KEY_CAN_SIGN (pk->pubkey_algo))
247 return CDK_Inv_Algo;
248 if (pk->timestamp > sig->timestamp || pk->timestamp > cur_time)
249 return CDK_Time_Conflict;
251 if (r_expired && pk->expiredate
252 && (pk->expiredate + pk->timestamp) > cur_time)
253 *r_expired = 1;
255 _cdk_hash_sig_data (sig, digest);
256 _gnutls_hash_output (digest, md);
258 if (md[0] != sig->digest_start[0] || md[1] != sig->digest_start[1])
260 gnutls_assert ();
261 return CDK_Chksum_Error;
264 rc = cdk_pk_verify (pk, sig, md);
265 cache_sig_result (sig, rc);
266 return rc;
270 /* Check the given key signature.
271 @knode is the key node and @snode the signature node. */
272 cdk_error_t
273 _cdk_pk_check_sig (cdk_keydb_hd_t keydb,
274 cdk_kbnode_t knode, cdk_kbnode_t snode, int *is_selfsig,
275 char **ret_uid)
277 digest_hd_st md;
278 int err;
279 cdk_pubkey_t pk;
280 cdk_pkt_signature_t sig;
281 cdk_kbnode_t node;
282 cdk_error_t rc = 0;
283 int is_expired;
285 if (!knode || !snode)
287 gnutls_assert ();
288 return CDK_Inv_Value;
291 if (is_selfsig)
292 *is_selfsig = 0;
293 if ((knode->pkt->pkttype != CDK_PKT_PUBLIC_KEY &&
294 knode->pkt->pkttype != CDK_PKT_PUBLIC_SUBKEY) ||
295 snode->pkt->pkttype != CDK_PKT_SIGNATURE)
297 gnutls_assert ();
298 return CDK_Inv_Value;
300 pk = knode->pkt->pkt.public_key;
301 sig = snode->pkt->pkt.signature;
303 err = _gnutls_hash_init (&md, sig->digest_algo);
304 if (err < 0)
306 gnutls_assert ();
307 return map_gnutls_error (err);
310 is_expired = 0;
311 if (sig->sig_class == 0x20)
312 { /* key revocation */
313 cdk_kbnode_hash (knode, &md, 0, 0, 0);
314 rc = _cdk_sig_check (pk, sig, &md, &is_expired);
316 else if (sig->sig_class == 0x28)
317 { /* subkey revocation */
318 node = cdk_kbnode_find_prev (knode, snode, CDK_PKT_PUBLIC_SUBKEY);
319 if (!node)
320 { /* no subkey for subkey revocation packet */
321 gnutls_assert ();
322 rc = CDK_Error_No_Key;
323 goto fail;
325 cdk_kbnode_hash (knode, &md, 0, 0, 0);
326 cdk_kbnode_hash (node, &md, 0, 0, 0);
327 rc = _cdk_sig_check (pk, sig, &md, &is_expired);
329 else if (sig->sig_class == 0x18 || sig->sig_class == 0x19)
330 { /* primary/secondary key binding */
331 node = cdk_kbnode_find_prev (knode, snode, CDK_PKT_PUBLIC_SUBKEY);
332 if (!node)
333 { /* no subkey for subkey binding packet */
334 gnutls_assert ();
335 rc = CDK_Error_No_Key;
336 goto fail;
338 cdk_kbnode_hash (knode, &md, 0, 0, 0);
339 cdk_kbnode_hash (node, &md, 0, 0, 0);
340 rc = _cdk_sig_check (pk, sig, &md, &is_expired);
342 else if (sig->sig_class == 0x1F)
343 { /* direct key signature */
344 cdk_kbnode_hash (knode, &md, 0, 0, 0);
345 rc = _cdk_sig_check (pk, sig, &md, &is_expired);
347 else
348 { /* all other classes */
349 cdk_pkt_userid_t uid;
350 node = cdk_kbnode_find_prev (knode, snode, CDK_PKT_USER_ID);
351 if (!node)
352 { /* no user ID for key signature packet */
353 gnutls_assert ();
354 rc = CDK_Error_No_Key;
355 goto fail;
358 uid = node->pkt->pkt.user_id;
359 if (ret_uid)
361 *ret_uid = uid->name;
363 cdk_kbnode_hash (knode, &md, 0, 0, 0);
364 cdk_kbnode_hash (node, &md, sig->version == 4, 0, 0);
366 if (pk->keyid[0] == sig->keyid[0] && pk->keyid[1] == sig->keyid[1])
368 rc = _cdk_sig_check (pk, sig, &md, &is_expired);
369 if (is_selfsig)
370 *is_selfsig = 1;
372 else if (keydb != NULL)
374 cdk_pubkey_t sig_pk;
375 rc = cdk_keydb_get_pk (keydb, sig->keyid, &sig_pk);
376 if (!rc)
377 rc = _cdk_sig_check (sig_pk, sig, &md, &is_expired);
378 cdk_pk_release (sig_pk);
381 fail:
382 _gnutls_hash_deinit (&md, NULL);
383 return rc;
386 struct verify_uid
388 const char *name;
389 int nsigs;
390 struct verify_uid *next;
393 static int
394 uid_list_add_sig (struct verify_uid **list, const char *uid,
395 unsigned int flag)
397 if (*list == NULL)
399 *list = cdk_calloc (1, sizeof (struct verify_uid));
400 if (*list == NULL)
401 return CDK_Out_Of_Core;
402 (*list)->name = uid;
404 if (flag != 0)
405 (*list)->nsigs++;
407 else
409 struct verify_uid *p, *prev_p = NULL;
410 int found = 0;
412 p = *list;
414 while (p != NULL)
416 if (strcmp (uid, p->name) == 0)
418 found = 1;
419 break;
421 prev_p = p;
422 p = p->next;
425 if (found == 0)
426 { /* not found add to the last */
427 prev_p->next = cdk_calloc (1, sizeof (struct verify_uid));
428 if (prev_p->next == NULL)
429 return CDK_Out_Of_Core;
430 prev_p->next->name = uid;
431 if (flag != 0)
432 prev_p->next->nsigs++;
434 else
435 { /* found... increase sigs */
436 if (flag != 0)
437 p->nsigs++;
441 return CDK_Success;
444 static void
445 uid_list_free (struct verify_uid *list)
447 struct verify_uid *p, *p1;
449 p = list;
450 while (p != NULL)
452 p1 = p->next;
453 cdk_free (p);
454 p = p1;
458 /* returns non (0) if all UIDs in the list have at least one
459 * signature. If the list is empty or no signatures are present
460 * a (0) value is returned.
462 static int
463 uid_list_all_signed (struct verify_uid *list)
465 struct verify_uid *p;
467 if (list == NULL)
468 return 0;
470 p = list;
471 while (p != NULL)
473 if (p->nsigs == 0)
475 return 0;
477 p = p->next;
479 return 1; /* all signed */
483 * cdk_pk_check_sigs:
484 * @key: the public key
485 * @hd: an optinal key database handle
486 * @r_status: variable to store the status of the key
488 * Check all signatures. When no key is available for checking, the
489 * sigstat is marked as 'NOKEY'. The @r_status contains the key flags
490 * which are or-ed or (0) when there are no flags.
492 cdk_error_t
493 cdk_pk_check_sigs (cdk_kbnode_t key, cdk_keydb_hd_t keydb, int *r_status)
495 cdk_pkt_signature_t sig;
496 cdk_kbnode_t node;
497 cdk_error_t rc;
498 u32 keyid;
499 int key_status, is_selfsig = 0;
500 struct verify_uid *uid_list = NULL;
501 char *uid_name;
503 if (!key || !r_status)
505 gnutls_assert ();
506 return CDK_Inv_Value;
509 *r_status = 0;
510 node = cdk_kbnode_find (key, CDK_PKT_PUBLIC_KEY);
511 if (!node)
513 gnutls_assert ();
514 return CDK_Error_No_Key;
517 key_status = 0;
518 /* Continue with the signature check but adjust the
519 key status flags accordingly. */
520 if (node->pkt->pkt.public_key->is_revoked)
521 key_status |= CDK_KEY_REVOKED;
522 if (node->pkt->pkt.public_key->has_expired)
523 key_status |= CDK_KEY_EXPIRED;
524 rc = 0;
526 keyid = cdk_pk_get_keyid (node->pkt->pkt.public_key, NULL);
527 for (node = key; node; node = node->next)
529 if (node->pkt->pkttype != CDK_PKT_SIGNATURE)
530 continue;
531 sig = node->pkt->pkt.signature;
532 rc = _cdk_pk_check_sig (keydb, key, node, &is_selfsig, &uid_name);
534 if (rc && rc != CDK_Error_No_Key)
536 /* It might be possible that a single signature has been
537 corrupted, thus we do not consider it a problem when
538 one ore more signatures are bad. But at least the self
539 signature has to be valid. */
540 if (is_selfsig)
542 key_status |= CDK_KEY_INVALID;
543 break;
547 _cdk_log_debug ("signature %s: signer %08X keyid %08X\n",
548 rc == CDK_Bad_Sig ? "BAD" : "good",
549 (unsigned int) sig->keyid[1], (unsigned int) keyid);
551 if (IS_UID_SIG (sig) && uid_name != NULL)
553 /* add every uid in the uid list. Only consider valid:
554 * - verification was ok
555 * - not a selfsig
557 rc =
558 uid_list_add_sig (&uid_list, uid_name,
559 (rc == CDK_Success && is_selfsig == 0) ? 1 : 0);
560 if (rc != CDK_Success)
562 gnutls_assert ();
563 goto exit;
569 if (uid_list_all_signed (uid_list) == 0)
570 key_status |= CDK_KEY_NOSIGNER;
571 *r_status = key_status;
572 if (rc == CDK_Error_No_Key)
573 rc = 0;
575 exit:
576 uid_list_free (uid_list);
577 return rc;
582 * cdk_pk_check_self_sig:
583 * @key: the key node
584 * @r_status: output the status of the key.
586 * A convenient function to make sure the key is valid.
587 * Valid means the self signature is ok.
589 cdk_error_t
590 cdk_pk_check_self_sig (cdk_kbnode_t key, int *r_status)
592 cdk_pkt_signature_t sig;
593 cdk_kbnode_t node;
594 cdk_error_t rc;
595 u32 keyid[2], sigid[2];
596 int is_selfsig, sig_ok;
597 cdk_kbnode_t p, ctx = NULL;
598 cdk_packet_t pkt;
600 if (!key || !r_status)
601 return CDK_Inv_Value;
603 cdk_pk_get_keyid (key->pkt->pkt.public_key, keyid);
605 while ((p = cdk_kbnode_walk (key, &ctx, 0)))
607 pkt = cdk_kbnode_get_packet (p);
608 if (pkt->pkttype != CDK_PKT_PUBLIC_SUBKEY
609 && pkt->pkttype != CDK_PKT_PUBLIC_KEY)
610 continue;
612 /* FIXME: we should set expire/revoke here also but callers
613 expect CDK_KEY_VALID=0 if the key is okay. */
614 sig_ok = 0;
615 for (node = p; node; node = node->next)
617 if (node->pkt->pkttype != CDK_PKT_SIGNATURE)
618 continue;
619 sig = node->pkt->pkt.signature;
621 cdk_sig_get_keyid (sig, sigid);
622 if (sigid[0] != keyid[0] || sigid[1] != keyid[1])
623 continue;
624 /* FIXME: Now we check all self signatures. */
625 rc = _cdk_pk_check_sig (NULL, p, node, &is_selfsig, NULL);
626 if (rc)
628 *r_status = CDK_KEY_INVALID;
629 return rc;
631 else /* For each valid self sig we increase this counter. */
632 sig_ok++;
635 /* A key without a self signature is not valid. At least one
636 * signature for the given key has to be found.
638 if (!sig_ok)
640 *r_status = CDK_KEY_INVALID;
641 return CDK_General_Error;
645 /* No flags indicate a valid key. */
646 *r_status = CDK_KEY_VALID;
648 return 0;