gpg: Finish experimental support for Ed25519.
[gnupg.git] / g10 / sig-check.c
1 /* sig-check.c -  Check a signature
2  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003,
3  *               2004, 2006 Free Software Foundation, Inc.
4  *
5  * This file is part of GnuPG.
6  *
7  * GnuPG is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * GnuPG is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <assert.h>
26
27 #include "gpg.h"
28 #include "util.h"
29 #include "packet.h"
30 #include "keydb.h"
31 #include "main.h"
32 #include "status.h"
33 #include "i18n.h"
34 #include "options.h"
35 #include "pkglue.h"
36
37 /* Context used by the compare function. */
38 struct cmp_help_context_s
39 {
40   PKT_signature *sig;
41   gcry_md_hd_t md;
42 };
43
44
45
46 static int do_check( PKT_public_key *pk, PKT_signature *sig,
47                      gcry_md_hd_t digest,
48                      int *r_expired, int *r_revoked, PKT_public_key *ret_pk);
49
50 /****************
51  * Check the signature which is contained in SIG.
52  * The MD_HANDLE should be currently open, so that this function
53  * is able to append some data, before finalizing the digest.
54  */
55 int
56 signature_check (PKT_signature *sig, gcry_md_hd_t digest)
57 {
58     return signature_check2( sig, digest, NULL, NULL, NULL, NULL );
59 }
60
61 int
62 signature_check2 (PKT_signature *sig, gcry_md_hd_t digest, u32 *r_expiredate,
63                   int *r_expired, int *r_revoked, PKT_public_key *ret_pk )
64 {
65     PKT_public_key *pk = xmalloc_clear( sizeof *pk );
66     int rc=0;
67
68     if ( (rc=openpgp_md_test_algo(sig->digest_algo)) )
69       ; /* We don't have this digest. */
70     else if ((rc=openpgp_pk_test_algo(sig->pubkey_algo)))
71       ; /* We don't have this pubkey algo. */
72     else if (!gcry_md_is_enabled (digest,sig->digest_algo))
73       {
74         /* Sanity check that the md has a context for the hash that the
75            sig is expecting.  This can happen if a onepass sig header does
76            not match the actual sig, and also if the clearsign "Hash:"
77            header is missing or does not match the actual sig. */
78
79         log_info(_("WARNING: signature digest conflict in message\n"));
80         rc=G10ERR_GENERAL;
81       }
82     else if( get_pubkey( pk, sig->keyid ) )
83         rc = G10ERR_NO_PUBKEY;
84     else if(!pk->flags.valid && !pk->flags.primary)
85         rc=G10ERR_BAD_PUBKEY; /* you cannot have a good sig from an
86                                  invalid subkey */
87     else
88       {
89         if(r_expiredate)
90           *r_expiredate = pk->expiredate;
91
92         rc = do_check( pk, sig, digest, r_expired, r_revoked, ret_pk );
93
94         /* Check the backsig.  This is a 0x19 signature from the
95            subkey on the primary key.  The idea here is that it should
96            not be possible for someone to "steal" subkeys and claim
97            them as their own.  The attacker couldn't actually use the
98            subkey, but they could try and claim ownership of any
99            signaures issued by it. */
100         if(rc==0 && !pk->flags.primary && pk->flags.backsig < 2)
101           {
102             if (!pk->flags.backsig)
103               {
104                 log_info(_("WARNING: signing subkey %s is not"
105                            " cross-certified\n"),keystr_from_pk(pk));
106                 log_info(_("please see %s for more information\n"),
107                          "http://www.gnupg.org/faq/subkey-cross-certify.html");
108                 /* --require-cross-certification makes this warning an
109                      error.  TODO: change the default to require this
110                      after more keys have backsigs. */
111                 if(opt.flags.require_cross_cert)
112                   rc=G10ERR_GENERAL;
113               }
114             else if(pk->flags.backsig == 1)
115               {
116                 log_info(_("WARNING: signing subkey %s has an invalid"
117                            " cross-certification\n"),keystr_from_pk(pk));
118                 rc=G10ERR_GENERAL;
119               }
120           }
121       }
122
123     free_public_key( pk );
124
125     if( !rc && sig->sig_class < 2 && is_status_enabled() ) {
126         /* This signature id works best with DLP algorithms because
127          * they use a random parameter for every signature.  Instead of
128          * this sig-id we could have also used the hash of the document
129          * and the timestamp, but the drawback of this is, that it is
130          * not possible to sign more than one identical document within
131          * one second.  Some remote batch processing applications might
132          * like this feature here.
133          *
134          * Note that before 2.0.10, we used RIPE-MD160 for the hash
135          * and accidently didn't include the timestamp and algorithm
136          * information in the hash.  Given that this feature is not
137          * commonly used and that a replay attacks detection should
138          * not solely be based on this feature (because it does not
139          * work with RSA), we take the freedom and switch to SHA-1
140          * with 2.0.10 to take advantage of hardware supported SHA-1
141          * implementations.  We also include the missing information
142          * in the hash.  Note also the SIG_ID as computed by gpg 1.x
143          * and gpg 2.x didn't matched either because 2.x used to print
144          * MPIs not in PGP format.  */
145         u32 a = sig->timestamp;
146         int nsig = pubkey_get_nsig( sig->pubkey_algo );
147         unsigned char *p, *buffer;
148         size_t n, nbytes;
149         int i;
150         char hashbuf[20];
151
152         nbytes = 6;
153         for (i=0; i < nsig; i++ )
154           {
155             if (gcry_mpi_print (GCRYMPI_FMT_USG, NULL, 0, &n, sig->data[i]))
156               BUG();
157             nbytes += n;
158           }
159
160         /* Make buffer large enough to be later used as output buffer.  */
161         if (nbytes < 100)
162           nbytes = 100;
163         nbytes += 10;  /* Safety margin.  */
164
165         /* Fill and hash buffer.  */
166         buffer = p = xmalloc (nbytes);
167         *p++ = sig->pubkey_algo;
168         *p++ = sig->digest_algo;
169         *p++ = (a >> 24) & 0xff;
170         *p++ = (a >> 16) & 0xff;
171         *p++ = (a >>  8) & 0xff;
172         *p++ =  a & 0xff;
173         nbytes -= 6;
174         for (i=0; i < nsig; i++ )
175           {
176             if (gcry_mpi_print (GCRYMPI_FMT_PGP, p, nbytes, &n, sig->data[i]))
177               BUG();
178             p += n;
179             nbytes -= n;
180           }
181         gcry_md_hash_buffer (GCRY_MD_SHA1, hashbuf, buffer, p-buffer);
182
183         p = make_radix64_string (hashbuf, 20);
184         sprintf (buffer, "%s %s %lu",
185                  p, strtimestamp (sig->timestamp), (ulong)sig->timestamp);
186         xfree (p);
187         write_status_text (STATUS_SIG_ID, buffer);
188         xfree (buffer);
189     }
190
191     return rc;
192 }
193
194
195 static int
196 do_check_messages( PKT_public_key *pk, PKT_signature *sig,
197                    int *r_expired, int *r_revoked )
198 {
199     u32 cur_time;
200
201     if(r_expired)
202       *r_expired = 0;
203     if(r_revoked)
204       *r_revoked = 0;
205
206     if( pk->timestamp > sig->timestamp )
207       {
208         ulong d = pk->timestamp - sig->timestamp;
209         log_info(d==1
210                  ?_("public key %s is %lu second newer than the signature\n")
211                  :_("public key %s is %lu seconds newer than the signature\n"),
212                  keystr_from_pk(pk),d );
213         if( !opt.ignore_time_conflict )
214           return G10ERR_TIME_CONFLICT; /* pubkey newer than signature */
215       }
216
217     cur_time = make_timestamp();
218     if( pk->timestamp > cur_time )
219       {
220         ulong d = pk->timestamp - cur_time;
221         log_info( d==1
222                   ? _("key %s was created %lu second"
223                       " in the future (time warp or clock problem)\n")
224                   : _("key %s was created %lu seconds"
225                       " in the future (time warp or clock problem)\n"),
226                   keystr_from_pk(pk),d );
227         if( !opt.ignore_time_conflict )
228           return G10ERR_TIME_CONFLICT;
229       }
230
231     /* Check whether the key has expired.  We check the has_expired
232        flag which is set after a full evaluation of the key (getkey.c)
233        as well as a simple compare to the current time in case the
234        merge has for whatever reasons not been done.  */
235     if( pk->has_expired || (pk->expiredate && pk->expiredate < cur_time)) {
236         char buf[11];
237         if (opt.verbose)
238           log_info(_("NOTE: signature key %s expired %s\n"),
239                    keystr_from_pk(pk), asctimestamp( pk->expiredate ) );
240         sprintf(buf,"%lu",(ulong)pk->expiredate);
241         write_status_text(STATUS_KEYEXPIRED,buf);
242         if(r_expired)
243           *r_expired = 1;
244     }
245
246     if (pk->flags.revoked)
247       {
248         if (opt.verbose)
249           log_info (_("NOTE: signature key %s has been revoked\n"),
250                     keystr_from_pk(pk));
251         if (r_revoked)
252           *r_revoked=1;
253       }
254
255     return 0;
256 }
257
258
259 static int
260 do_check( PKT_public_key *pk, PKT_signature *sig, gcry_md_hd_t digest,
261           int *r_expired, int *r_revoked, PKT_public_key *ret_pk )
262 {
263     gcry_mpi_t result = NULL;
264     int rc = 0;
265
266     if( (rc=do_check_messages(pk,sig,r_expired,r_revoked)) )
267         return rc;
268
269     if (sig->digest_algo == GCRY_MD_MD5
270         && !opt.flags.allow_weak_digest_algos)
271       {
272         static int shown;
273
274         if (!shown)
275           {
276             log_info
277               (_("Note: signatures using the %s algorithm are rejected\n"),
278                "MD5");
279             shown = 1;
280           }
281
282         return GPG_ERR_DIGEST_ALGO;
283       }
284
285     /* Make sure the digest algo is enabled (in case of a detached
286        signature).  */
287     gcry_md_enable (digest, sig->digest_algo);
288
289     /* Complete the digest. */
290     if( sig->version >= 4 )
291         gcry_md_putc( digest, sig->version );
292     gcry_md_putc( digest, sig->sig_class );
293     if( sig->version < 4 ) {
294         u32 a = sig->timestamp;
295         gcry_md_putc( digest, (a >> 24) & 0xff );
296         gcry_md_putc( digest, (a >> 16) & 0xff );
297         gcry_md_putc( digest, (a >>     8) & 0xff );
298         gcry_md_putc( digest,  a           & 0xff );
299     }
300     else {
301         byte buf[6];
302         size_t n;
303         gcry_md_putc( digest, sig->pubkey_algo );
304         gcry_md_putc( digest, sig->digest_algo );
305         if( sig->hashed ) {
306             n = sig->hashed->len;
307             gcry_md_putc (digest, (n >> 8) );
308             gcry_md_putc (digest,  n       );
309             gcry_md_write (digest, sig->hashed->data, n);
310             n += 6;
311         }
312         else {
313           /* Two octets for the (empty) length of the hashed
314              section. */
315           gcry_md_putc (digest, 0);
316           gcry_md_putc (digest, 0);
317           n = 6;
318         }
319         /* add some magic */
320         buf[0] = sig->version;
321         buf[1] = 0xff;
322         buf[2] = n >> 24;
323         buf[3] = n >> 16;
324         buf[4] = n >>  8;
325         buf[5] = n;
326         gcry_md_write( digest, buf, 6 );
327     }
328     gcry_md_final( digest );
329
330     result = encode_md_value (pk, digest, sig->digest_algo );
331     if (!result)
332         return G10ERR_GENERAL;
333     rc = pk_verify( pk->pubkey_algo, result, sig->data, pk->pkey );
334     gcry_mpi_release (result);
335
336     if( !rc && sig->flags.unknown_critical )
337       {
338         log_info(_("assuming bad signature from key %s"
339                    " due to an unknown critical bit\n"),keystr_from_pk(pk));
340         rc = G10ERR_BAD_SIGN;
341       }
342
343     if(!rc && ret_pk)
344       copy_public_key(ret_pk,pk);
345
346     return rc;
347 }
348
349
350
351 static void
352 hash_uid_node( KBNODE unode, gcry_md_hd_t md, PKT_signature *sig )
353 {
354     PKT_user_id *uid = unode->pkt->pkt.user_id;
355
356     assert( unode->pkt->pkttype == PKT_USER_ID );
357     if( uid->attrib_data ) {
358         if( sig->version >=4 ) {
359             byte buf[5];
360             buf[0] = 0xd1;                   /* packet of type 17 */
361             buf[1] = uid->attrib_len >> 24;  /* always use 4 length bytes */
362             buf[2] = uid->attrib_len >> 16;
363             buf[3] = uid->attrib_len >>  8;
364             buf[4] = uid->attrib_len;
365             gcry_md_write( md, buf, 5 );
366         }
367         gcry_md_write( md, uid->attrib_data, uid->attrib_len );
368     }
369     else {
370         if( sig->version >=4 ) {
371             byte buf[5];
372             buf[0] = 0xb4;            /* indicates a userid packet */
373             buf[1] = uid->len >> 24;  /* always use 4 length bytes */
374             buf[2] = uid->len >> 16;
375             buf[3] = uid->len >>  8;
376             buf[4] = uid->len;
377             gcry_md_write( md, buf, 5 );
378         }
379         gcry_md_write( md, uid->name, uid->len );
380     }
381 }
382
383 static void
384 cache_sig_result ( PKT_signature *sig, int result )
385 {
386     if ( !result ) {
387         sig->flags.checked = 1;
388         sig->flags.valid = 1;
389     }
390     else if ( gpg_err_code (result) == GPG_ERR_BAD_SIGNATURE ) {
391         sig->flags.checked = 1;
392         sig->flags.valid = 0;
393     }
394     else {
395         sig->flags.checked = 0;
396         sig->flags.valid = 0;
397     }
398 }
399
400 /* Check the revocation keys to see if any of them have revoked our
401    pk.  sig is the revocation sig.  pk is the key it is on.  This code
402    will need to be modified if gpg ever becomes multi-threaded.  Note
403    that this guarantees that a designated revocation sig will never be
404    considered valid unless it is actually valid, as well as being
405    issued by a revocation key in a valid direct signature.  Note also
406    that this is written so that a revoked revoker can still issue
407    revocations: i.e. If A revokes B, but A is revoked, B is still
408    revoked.  I'm not completely convinced this is the proper behavior,
409    but it matches how PGP does it. -dms */
410
411 /* Returns 0 if sig is valid (i.e. pk is revoked), non-0 if not
412    revoked.  It is important that G10ERR_NO_PUBKEY is only returned
413    when a revocation signature is from a valid revocation key
414    designated in a revkey subpacket, but the revocation key itself
415    isn't present. */
416 int
417 check_revocation_keys(PKT_public_key *pk,PKT_signature *sig)
418 {
419   static int busy=0;
420   int i,rc=G10ERR_GENERAL;
421
422   assert(IS_KEY_REV(sig));
423   assert((sig->keyid[0]!=pk->keyid[0]) || (sig->keyid[0]!=pk->keyid[1]));
424
425   if (busy)
426     {
427       /* Return an error (i.e. not revoked), but mark the pk as
428          uncacheable as we don't really know its revocation status
429          until it is checked directly.  */
430       pk->flags.dont_cache = 1;
431       return rc;
432     }
433
434   busy=1;
435
436   /*  printf("looking at %08lX with a sig from %08lX\n",(ulong)pk->keyid[1],
437       (ulong)sig->keyid[1]); */
438
439   /* is the issuer of the sig one of our revokers? */
440   if( !pk->revkey && pk->numrevkeys )
441      BUG();
442   else
443       for(i=0;i<pk->numrevkeys;i++)
444         {
445           u32 keyid[2];
446
447           keyid_from_fingerprint(pk->revkey[i].fpr,MAX_FINGERPRINT_LEN,keyid);
448
449           if(keyid[0]==sig->keyid[0] && keyid[1]==sig->keyid[1])
450             {
451               gcry_md_hd_t md;
452
453               if (gcry_md_open (&md, sig->digest_algo, 0))
454                 BUG ();
455               hash_public_key(md,pk);
456               rc=signature_check(sig,md);
457               cache_sig_result(sig,rc);
458               gcry_md_close (md);
459               break;
460             }
461         }
462
463   busy=0;
464
465   return rc;
466 }
467
468 /* Backsigs (0x19) have the same format as binding sigs (0x18), but
469    this function is simpler than check_key_signature in a few ways.
470    For example, there is no support for expiring backsigs since it is
471    questionable what such a thing actually means.  Note also that the
472    sig cache check here, unlike other sig caches in GnuPG, is not
473    persistent. */
474 int
475 check_backsig(PKT_public_key *main_pk,PKT_public_key *sub_pk,
476               PKT_signature *backsig)
477 {
478   gcry_md_hd_t md;
479   int rc;
480
481   /* Always check whether the algorithm is available.  Although
482      gcry_md_open woyuld throw an error, some libgcrypt versions will
483      print a debug message in that case too. */
484   if ((rc=openpgp_md_test_algo (backsig->digest_algo)))
485     return rc;
486
487   if(!opt.no_sig_cache && backsig->flags.checked)
488     return backsig->flags.valid? 0 : gpg_error (GPG_ERR_BAD_SIGNATURE);
489
490   rc = gcry_md_open (&md, backsig->digest_algo,0);
491   if (!rc)
492     {
493       hash_public_key(md,main_pk);
494       hash_public_key(md,sub_pk);
495       rc=do_check(sub_pk,backsig,md,NULL,NULL,NULL);
496       cache_sig_result(backsig,rc);
497       gcry_md_close(md);
498     }
499
500   return rc;
501 }
502
503
504 /****************
505  * check the signature pointed to by NODE. This is a key signature.
506  * If the function detects a self-signature, it uses the PK from
507  * ROOT and does not read any public key.
508  */
509 int
510 check_key_signature( KBNODE root, KBNODE node, int *is_selfsig )
511 {
512   return check_key_signature2(root, node, NULL, NULL, is_selfsig, NULL, NULL );
513 }
514
515 /* If check_pk is set, then use it to check the signature in node
516    rather than getting it from root or the keydb.  If ret_pk is set,
517    fill in the public key that was used to verify the signature.
518    ret_pk is only meaningful when the verification was successful. */
519 /* TODO: add r_revoked here as well.  It has the same problems as
520    r_expiredate and r_expired and the cache. */
521 int
522 check_key_signature2( KBNODE root, KBNODE node, PKT_public_key *check_pk,
523                       PKT_public_key *ret_pk, int *is_selfsig,
524                       u32 *r_expiredate, int *r_expired )
525 {
526     gcry_md_hd_t md;
527     PKT_public_key *pk;
528     PKT_signature *sig;
529     int algo;
530     int rc;
531
532     if( is_selfsig )
533         *is_selfsig = 0;
534     if( r_expiredate )
535         *r_expiredate = 0;
536     if( r_expired )
537         *r_expired = 0;
538     assert( node->pkt->pkttype == PKT_SIGNATURE );
539     assert( root->pkt->pkttype == PKT_PUBLIC_KEY );
540
541     pk = root->pkt->pkt.public_key;
542     sig = node->pkt->pkt.signature;
543     algo = sig->digest_algo;
544
545     /* Check whether we have cached the result of a previous signature
546        check.  Note that we may no longer have the pubkey or hash
547        needed to verify a sig, but can still use the cached value.  A
548        cache refresh detects and clears these cases. */
549     if ( !opt.no_sig_cache ) {
550         if (sig->flags.checked) { /*cached status available*/
551             if( is_selfsig ) {
552                 u32 keyid[2];
553
554                 keyid_from_pk( pk, keyid );
555                 if( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1] )
556                     *is_selfsig = 1;
557             }
558             /* BUG: This is wrong for non-self-sigs.. needs to be the
559                actual pk */
560             if((rc=do_check_messages(pk,sig,r_expired,NULL)))
561               return rc;
562             return sig->flags.valid? 0 : gpg_error (GPG_ERR_BAD_SIGNATURE);
563         }
564     }
565
566     if( (rc=openpgp_pk_test_algo(sig->pubkey_algo)) )
567         return rc;
568     if( (rc=openpgp_md_test_algo(algo)) )
569         return rc;
570
571     if( sig->sig_class == 0x20 ) { /* key revocation */
572         u32 keyid[2];
573         keyid_from_pk( pk, keyid );
574
575         /* is it a designated revoker? */
576         if(keyid[0]!=sig->keyid[0] || keyid[1]!=sig->keyid[1])
577           rc=check_revocation_keys(pk,sig);
578         else
579           {
580             if (gcry_md_open (&md, algo, 0 ))
581               BUG ();
582             hash_public_key( md, pk );
583             rc = do_check( pk, sig, md, r_expired, NULL, ret_pk );
584             cache_sig_result ( sig, rc );
585             gcry_md_close(md);
586           }
587     }
588     else if( sig->sig_class == 0x28 ) { /* subkey revocation */
589         KBNODE snode = find_prev_kbnode( root, node, PKT_PUBLIC_SUBKEY );
590
591         if( snode ) {
592             if (gcry_md_open (&md, algo, 0))
593               BUG ();
594             hash_public_key( md, pk );
595             hash_public_key( md, snode->pkt->pkt.public_key );
596             rc = do_check( pk, sig, md, r_expired, NULL, ret_pk );
597             cache_sig_result ( sig, rc );
598             gcry_md_close(md);
599         }
600         else
601           {
602             if (opt.verbose)
603               log_info (_("key %s: no subkey for subkey"
604                           " revocation signature\n"),keystr_from_pk(pk));
605             rc = G10ERR_SIG_CLASS;
606           }
607     }
608     else if( sig->sig_class == 0x18 ) { /* key binding */
609         KBNODE snode = find_prev_kbnode( root, node, PKT_PUBLIC_SUBKEY );
610
611         if( snode ) {
612             if( is_selfsig ) {  /* does this make sense????? */
613                 u32 keyid[2];   /* it should always be a selfsig */
614
615                 keyid_from_pk( pk, keyid );
616                 if( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1] )
617                     *is_selfsig = 1;
618             }
619             if (gcry_md_open (&md, algo, 0))
620               BUG ();
621             hash_public_key( md, pk );
622             hash_public_key( md, snode->pkt->pkt.public_key );
623             rc = do_check( pk, sig, md, r_expired, NULL, ret_pk );
624             cache_sig_result ( sig, rc );
625             gcry_md_close(md);
626         }
627         else
628           {
629             if (opt.verbose)
630               log_info(_("key %s: no subkey for subkey"
631                          " binding signature\n"),keystr_from_pk(pk));
632             rc = G10ERR_SIG_CLASS;
633           }
634     }
635     else if( sig->sig_class == 0x1f ) { /* direct key signature */
636         if (gcry_md_open (&md, algo, 0 ))
637           BUG ();
638         hash_public_key( md, pk );
639         rc = do_check( pk, sig, md, r_expired, NULL, ret_pk );
640         cache_sig_result ( sig, rc );
641         gcry_md_close(md);
642     }
643     else { /* all other classes */
644         KBNODE unode = find_prev_kbnode( root, node, PKT_USER_ID );
645
646         if( unode ) {
647             u32 keyid[2];
648
649             keyid_from_pk( pk, keyid );
650             if (gcry_md_open (&md, algo, 0 ))
651               BUG ();
652             hash_public_key( md, pk );
653             hash_uid_node( unode, md, sig );
654             if( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1] )
655               {
656                 if( is_selfsig )
657                   *is_selfsig = 1;
658                 rc = do_check( pk, sig, md, r_expired, NULL, ret_pk );
659               }
660             else if (check_pk)
661               rc=do_check(check_pk,sig,md,r_expired,NULL,ret_pk);
662             else
663               rc=signature_check2(sig,md,r_expiredate,r_expired,NULL,ret_pk);
664
665             cache_sig_result ( sig, rc );
666             gcry_md_close(md);
667         }
668         else
669           {
670             if (!opt.quiet)
671               log_info ("key %s: no user ID for key signature packet"
672                         " of class %02x\n",keystr_from_pk(pk),sig->sig_class);
673             rc = G10ERR_SIG_CLASS;
674           }
675     }
676
677     return rc;
678 }