Tizen 2.0 Release
[external/libgnutls26.git] / lib / opencdk / sig-check.c
1 /* sig-check.c - Check signatures
2  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2007, 2008, 2010
3  * Free Software Foundation, Inc.
4  *
5  * Author: Timo Schulz
6  *
7  * This file is part of OpenCDK.
8  *
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.
13  *
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.
18  *
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,
22  * USA
23  *
24  */
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28 #include <stdio.h>
29 #include <assert.h>
30
31 #include "opencdk.h"
32 #include "main.h"
33 #include "packet.h"
34
35 /* Hash all multi precision integers of the key PK with the given
36    message digest context MD. */
37 static int
38 hash_mpibuf (cdk_pubkey_t pk, digest_hd_st * md, int usefpr)
39 {
40   byte buf[MAX_MPI_BYTES];      /* FIXME: do not use hardcoded length. */
41   size_t nbytes;
42   size_t i, npkey;
43   int err;
44
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++)
50     {
51       nbytes = MAX_MPI_BYTES;
52       err = _gnutls_mpi_print_pgp (pk->mpi[i], buf, &nbytes);
53
54       if (err < 0)
55         {
56           gnutls_assert ();
57           return map_gnutls_error (err);
58         }
59
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);
64     }
65   return 0;
66 }
67
68
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. */
72 cdk_error_t
73 _cdk_hash_pubkey (cdk_pubkey_t pk, digest_hd_st * md, int usefpr)
74 {
75   byte buf[12];
76   size_t i, n, npkey;
77
78   if (!pk || !md)
79     return CDK_Inv_Value;
80
81   if (usefpr && pk->version < 4 && is_RSA (pk->pubkey_algo))
82     return hash_mpibuf (pk, md, 1);
83
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;
90
91   i = 0;
92   buf[i++] = 0x99;
93   buf[i++] = n >> 8;
94   buf[i++] = n >> 0;
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;
100
101   if (pk->version < 4)
102     {
103       u16 a = 0;
104
105       /* Convert the expiration date into days. */
106       if (pk->expiredate)
107         a = (u16) ((pk->expiredate - pk->timestamp) / 86400L);
108       buf[i++] = a >> 8;
109       buf[i++] = a;
110     }
111   buf[i++] = pk->pubkey_algo;
112   _gnutls_hash (md, buf, i);
113   return hash_mpibuf (pk, md, 0);
114 }
115
116
117 /* Hash the user ID @uid with the given message digest @md.
118    Use openpgp mode if @is_v4 is 1. */
119 cdk_error_t
120 _cdk_hash_userid (cdk_pkt_userid_t uid, int is_v4, digest_hd_st * md)
121 {
122   const byte *data;
123   byte buf[5];
124   u32 dlen;
125
126   if (!uid || !md)
127     return CDK_Inv_Value;
128
129   if (!is_v4)
130     {
131       _gnutls_hash (md, (byte *) uid->name, uid->len);
132       return 0;
133     }
134
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;
138   buf[1] = dlen >> 24;
139   buf[2] = dlen >> 16;
140   buf[3] = dlen >> 8;
141   buf[4] = dlen >> 0;
142   _gnutls_hash (md, buf, 5);
143   _gnutls_hash (md, data, dlen);
144   return 0;
145 }
146
147
148 /* Hash all parts of the signature which are needed to derive
149    the correct message digest to verify the sig. */
150 cdk_error_t
151 _cdk_hash_sig_data (cdk_pkt_signature_t sig, digest_hd_st * md)
152 {
153   byte buf[4];
154   byte tmp;
155
156   if (!sig || !md)
157     return CDK_Inv_Value;
158
159   if (sig->version == 4)
160     _gnutls_hash (md, &sig->version, 1);
161
162   _gnutls_hash (md, &sig->sig_class, 1);
163   if (sig->version < 4)
164     {
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);
170     }
171   else
172     {
173       size_t n;
174
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)
180         {
181           byte *p = _cdk_subpkt_get_array (sig->hashed, 0, &n);
182           assert (p != NULL);
183           buf[0] = n >> 8;
184           buf[1] = n >> 0;
185           _gnutls_hash (md, buf, 2);
186           _gnutls_hash (md, p, n);
187           cdk_free (p);
188           sig->hashed_size = n;
189           n = sig->hashed_size + 6;
190         }
191       else
192         {
193           tmp = 0x00;
194           _gnutls_hash (md, &tmp, 1);
195           _gnutls_hash (md, &tmp, 1);
196           n = 6;
197         }
198       _gnutls_hash (md, &sig->version, 1);
199       tmp = 0xff;
200       _gnutls_hash (md, &tmp, 1);
201       buf[0] = n >> 24;
202       buf[1] = n >> 16;
203       buf[2] = n >> 8;
204       buf[3] = n >> 0;
205       _gnutls_hash (md, buf, 4);
206     }
207   return 0;
208 }
209
210
211 /* Cache the signature result and store it inside the sig. */
212 static void
213 cache_sig_result (cdk_pkt_signature_t sig, int res)
214 {
215   sig->flags.checked = 0;
216   sig->flags.valid = 0;
217   if (res == 0)
218     {
219       sig->flags.checked = 1;
220       sig->flags.valid = 1;
221     }
222   else if (res == CDK_Bad_Sig)
223     {
224       sig->flags.checked = 1;
225       sig->flags.valid = 0;
226     }
227 }
228
229
230 /* Check the given signature @sig with the public key @pk.
231    Use the digest handle @digest. */
232 cdk_error_t
233 _cdk_sig_check (cdk_pubkey_t pk, cdk_pkt_signature_t sig,
234                 digest_hd_st * digest, int *r_expired)
235 {
236   cdk_error_t rc;
237   byte md[MAX_DIGEST_LEN];
238   time_t cur_time = (u32) gnutls_time (NULL);
239
240   if (!pk || !sig || !digest)
241     {
242       gnutls_assert ();
243       return CDK_Inv_Value;
244     }
245
246   if (sig->flags.checked)
247     return sig->flags.valid ? 0 : CDK_Bad_Sig;
248   if (!KEY_CAN_SIGN (pk->pubkey_algo))
249     return CDK_Inv_Algo;
250   if (pk->timestamp > sig->timestamp || pk->timestamp > cur_time)
251     return CDK_Time_Conflict;
252
253   if (r_expired && pk->expiredate
254       && (pk->expiredate + pk->timestamp) > cur_time)
255     *r_expired = 1;
256
257   _cdk_hash_sig_data (sig, digest);
258   _gnutls_hash_output (digest, md);
259
260   if (md[0] != sig->digest_start[0] || md[1] != sig->digest_start[1])
261     {
262       gnutls_assert ();
263       return CDK_Chksum_Error;
264     }
265
266   rc = cdk_pk_verify (pk, sig, md);
267   cache_sig_result (sig, rc);
268   return rc;
269 }
270
271
272 /* Check the given key signature.
273    @knode is the key node and @snode the signature node. */
274 cdk_error_t
275 _cdk_pk_check_sig (cdk_keydb_hd_t keydb,
276                    cdk_kbnode_t knode, cdk_kbnode_t snode, int *is_selfsig,
277                    char **ret_uid)
278 {
279   digest_hd_st md;
280   int err;
281   cdk_pubkey_t pk;
282   cdk_pkt_signature_t sig;
283   cdk_kbnode_t node;
284   cdk_error_t rc = 0;
285   int is_expired;
286
287   if (!knode || !snode)
288     {
289       gnutls_assert ();
290       return CDK_Inv_Value;
291     }
292
293   if (is_selfsig)
294     *is_selfsig = 0;
295   if ((knode->pkt->pkttype != CDK_PKT_PUBLIC_KEY &&
296        knode->pkt->pkttype != CDK_PKT_PUBLIC_SUBKEY) ||
297       snode->pkt->pkttype != CDK_PKT_SIGNATURE)
298     {
299       gnutls_assert ();
300       return CDK_Inv_Value;
301     }
302   pk = knode->pkt->pkt.public_key;
303   sig = snode->pkt->pkt.signature;
304
305   err = _gnutls_hash_init (&md, sig->digest_algo);
306   if (err < 0)
307     {
308       gnutls_assert ();
309       return map_gnutls_error (err);
310     }
311
312   is_expired = 0;
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);
317     }
318   else if (sig->sig_class == 0x28)
319     {                           /* subkey revocation */
320       node = cdk_kbnode_find_prev (knode, snode, CDK_PKT_PUBLIC_SUBKEY);
321       if (!node)
322         {                       /* no subkey for subkey revocation packet */
323           gnutls_assert ();
324           rc = CDK_Error_No_Key;
325           goto fail;
326         }
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);
330     }
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);
334       if (!node)
335         {                       /* no subkey for subkey binding packet */
336           gnutls_assert ();
337           rc = CDK_Error_No_Key;
338           goto fail;
339         }
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);
343     }
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);
348     }
349   else
350     {                           /* all other classes */
351       cdk_pkt_userid_t uid;
352       node = cdk_kbnode_find_prev (knode, snode, CDK_PKT_USER_ID);
353       if (!node)
354         {                       /* no user ID for key signature packet */
355           gnutls_assert ();
356           rc = CDK_Error_No_Key;
357           goto fail;
358         }
359
360       uid = node->pkt->pkt.user_id;
361       if (ret_uid)
362         {
363           *ret_uid = uid->name;
364         }
365       cdk_kbnode_hash (knode, &md, 0, 0, 0);
366       cdk_kbnode_hash (node, &md, sig->version == 4, 0, 0);
367
368       if (pk->keyid[0] == sig->keyid[0] && pk->keyid[1] == sig->keyid[1])
369         {
370           rc = _cdk_sig_check (pk, sig, &md, &is_expired);
371           if (is_selfsig)
372             *is_selfsig = 1;
373         }
374       else if (keydb != NULL)
375         {
376           cdk_pubkey_t sig_pk;
377           rc = cdk_keydb_get_pk (keydb, sig->keyid, &sig_pk);
378           if (!rc)
379             rc = _cdk_sig_check (sig_pk, sig, &md, &is_expired);
380           cdk_pk_release (sig_pk);
381         }
382     }
383 fail:
384   _gnutls_hash_deinit (&md, NULL);
385   return rc;
386 }
387
388 struct verify_uid
389 {
390   const char *name;
391   int nsigs;
392   struct verify_uid *next;
393 };
394
395 static int
396 uid_list_add_sig (struct verify_uid **list, const char *uid,
397                   unsigned int flag)
398 {
399   if (*list == NULL)
400     {
401       *list = cdk_calloc (1, sizeof (struct verify_uid));
402       if (*list == NULL)
403         return CDK_Out_Of_Core;
404       (*list)->name = uid;
405
406       if (flag != 0)
407         (*list)->nsigs++;
408     }
409   else
410     {
411       struct verify_uid *p, *prev_p = NULL;
412       int found = 0;
413
414       p = *list;
415
416       while (p != NULL)
417         {
418           if (strcmp (uid, p->name) == 0)
419             {
420               found = 1;
421               break;
422             }
423           prev_p = p;
424           p = p->next;
425         }
426
427       if (found == 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;
433           if (flag != 0)
434             prev_p->next->nsigs++;
435         }
436       else
437         {                       /* found... increase sigs */
438           if (flag != 0)
439             p->nsigs++;
440         }
441     }
442
443   return CDK_Success;
444 }
445
446 static void
447 uid_list_free (struct verify_uid *list)
448 {
449   struct verify_uid *p, *p1;
450
451   p = list;
452   while (p != NULL)
453     {
454       p1 = p->next;
455       cdk_free (p);
456       p = p1;
457     }
458 }
459
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.
463  */
464 static int
465 uid_list_all_signed (struct verify_uid *list)
466 {
467   struct verify_uid *p;
468
469   if (list == NULL)
470     return 0;
471
472   p = list;
473   while (p != NULL)
474     {
475       if (p->nsigs == 0)
476         {
477           return 0;
478         }
479       p = p->next;
480     }
481   return 1;                     /* all signed */
482 }
483
484 /**
485  * cdk_pk_check_sigs:
486  * @key: the public key
487  * @hd: an optinal key database handle
488  * @r_status: variable to store the status of the key
489  *
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.
493  **/
494 cdk_error_t
495 cdk_pk_check_sigs (cdk_kbnode_t key, cdk_keydb_hd_t keydb, int *r_status)
496 {
497   cdk_pkt_signature_t sig;
498   cdk_kbnode_t node;
499   cdk_error_t rc;
500   u32 keyid;
501   int key_status, is_selfsig = 0;
502   struct verify_uid *uid_list = NULL;
503   char *uid_name;
504
505   if (!key || !r_status)
506     {
507       gnutls_assert ();
508       return CDK_Inv_Value;
509     }
510
511   *r_status = 0;
512   node = cdk_kbnode_find (key, CDK_PKT_PUBLIC_KEY);
513   if (!node)
514     {
515       gnutls_assert ();
516       return CDK_Error_No_Key;
517     }
518
519   key_status = 0;
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;
526   rc = 0;
527
528   keyid = cdk_pk_get_keyid (node->pkt->pkt.public_key, NULL);
529   for (node = key; node; node = node->next)
530     {
531       if (node->pkt->pkttype != CDK_PKT_SIGNATURE)
532         continue;
533       sig = node->pkt->pkt.signature;
534       rc = _cdk_pk_check_sig (keydb, key, node, &is_selfsig, &uid_name);
535
536       if (rc && rc != CDK_Error_No_Key)
537         {
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. */
542           if (is_selfsig)
543             {
544               key_status |= CDK_KEY_INVALID;
545               break;
546             }
547         }
548
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);
552
553       if (IS_UID_SIG (sig) && uid_name != NULL)
554         {
555           /* add every uid in the uid list. Only consider valid:
556            * - verification was ok
557            * - not a selfsig
558            */
559           rc =
560             uid_list_add_sig (&uid_list, uid_name,
561                               (rc == CDK_Success && is_selfsig == 0) ? 1 : 0);
562           if (rc != CDK_Success)
563             {
564               gnutls_assert ();
565               goto exit;
566             }
567         }
568
569     }
570
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)
575     rc = 0;
576
577 exit:
578   uid_list_free (uid_list);
579   return rc;
580 }
581
582
583 /**
584  * cdk_pk_check_self_sig:
585  * @key: the key node
586  * @r_status: output the status of the key.
587  *
588  * A convenient function to make sure the key is valid.
589  * Valid means the self signature is ok.
590  **/
591 cdk_error_t
592 cdk_pk_check_self_sig (cdk_kbnode_t key, int *r_status)
593 {
594   cdk_pkt_signature_t sig;
595   cdk_kbnode_t node;
596   cdk_error_t rc;
597   u32 keyid[2], sigid[2];
598   int is_selfsig, sig_ok;
599   cdk_kbnode_t p, ctx = NULL;
600   cdk_packet_t pkt;
601
602   if (!key || !r_status)
603     return CDK_Inv_Value;
604
605   cdk_pk_get_keyid (key->pkt->pkt.public_key, keyid);
606
607   while ((p = cdk_kbnode_walk (key, &ctx, 0)))
608     {
609       pkt = cdk_kbnode_get_packet (p);
610       if (pkt->pkttype != CDK_PKT_PUBLIC_SUBKEY
611           && pkt->pkttype != CDK_PKT_PUBLIC_KEY)
612         continue;
613
614       /* FIXME: we should set expire/revoke here also but callers
615          expect CDK_KEY_VALID=0 if the key is okay. */
616       sig_ok = 0;
617       for (node = p; node; node = node->next)
618         {
619           if (node->pkt->pkttype != CDK_PKT_SIGNATURE)
620             continue;
621           sig = node->pkt->pkt.signature;
622
623           cdk_sig_get_keyid (sig, sigid);
624           if (sigid[0] != keyid[0] || sigid[1] != keyid[1])
625             continue;
626           /* FIXME: Now we check all self signatures. */
627           rc = _cdk_pk_check_sig (NULL, p, node, &is_selfsig, NULL);
628           if (rc)
629             {
630               *r_status = CDK_KEY_INVALID;
631               return rc;
632             }
633           else                  /* For each valid self sig we increase this counter. */
634             sig_ok++;
635         }
636
637       /* A key without a self signature is not valid. At least one
638        * signature for the given key has to be found.
639        */
640       if (!sig_ok)
641         {
642           *r_status = CDK_KEY_INVALID;
643           return CDK_General_Error;
644         }
645     }
646
647   /* No flags indicate a valid key. */
648   *r_status = CDK_KEY_VALID;
649
650   return 0;
651 }