gpg: Install the current release signing pubkey.
[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         print_md5_rejected_note ();
273         return GPG_ERR_DIGEST_ALGO;
274       }
275
276     /* Make sure the digest algo is enabled (in case of a detached
277        signature).  */
278     gcry_md_enable (digest, sig->digest_algo);
279
280     /* Complete the digest. */
281     if( sig->version >= 4 )
282         gcry_md_putc( digest, sig->version );
283     gcry_md_putc( digest, sig->sig_class );
284     if( sig->version < 4 ) {
285         u32 a = sig->timestamp;
286         gcry_md_putc( digest, (a >> 24) & 0xff );
287         gcry_md_putc( digest, (a >> 16) & 0xff );
288         gcry_md_putc( digest, (a >>     8) & 0xff );
289         gcry_md_putc( digest,  a           & 0xff );
290     }
291     else {
292         byte buf[6];
293         size_t n;
294         gcry_md_putc( digest, sig->pubkey_algo );
295         gcry_md_putc( digest, sig->digest_algo );
296         if( sig->hashed ) {
297             n = sig->hashed->len;
298             gcry_md_putc (digest, (n >> 8) );
299             gcry_md_putc (digest,  n       );
300             gcry_md_write (digest, sig->hashed->data, n);
301             n += 6;
302         }
303         else {
304           /* Two octets for the (empty) length of the hashed
305              section. */
306           gcry_md_putc (digest, 0);
307           gcry_md_putc (digest, 0);
308           n = 6;
309         }
310         /* add some magic */
311         buf[0] = sig->version;
312         buf[1] = 0xff;
313         buf[2] = n >> 24;
314         buf[3] = n >> 16;
315         buf[4] = n >>  8;
316         buf[5] = n;
317         gcry_md_write( digest, buf, 6 );
318     }
319     gcry_md_final( digest );
320
321     result = encode_md_value (pk, digest, sig->digest_algo );
322     if (!result)
323         return G10ERR_GENERAL;
324     rc = pk_verify( pk->pubkey_algo, result, sig->data, pk->pkey );
325     gcry_mpi_release (result);
326
327     if( !rc && sig->flags.unknown_critical )
328       {
329         log_info(_("assuming bad signature from key %s"
330                    " due to an unknown critical bit\n"),keystr_from_pk(pk));
331         rc = G10ERR_BAD_SIGN;
332       }
333
334     if(!rc && ret_pk)
335       copy_public_key(ret_pk,pk);
336
337     return rc;
338 }
339
340
341
342 static void
343 hash_uid_node( KBNODE unode, gcry_md_hd_t md, PKT_signature *sig )
344 {
345     PKT_user_id *uid = unode->pkt->pkt.user_id;
346
347     assert( unode->pkt->pkttype == PKT_USER_ID );
348     if( uid->attrib_data ) {
349         if( sig->version >=4 ) {
350             byte buf[5];
351             buf[0] = 0xd1;                   /* packet of type 17 */
352             buf[1] = uid->attrib_len >> 24;  /* always use 4 length bytes */
353             buf[2] = uid->attrib_len >> 16;
354             buf[3] = uid->attrib_len >>  8;
355             buf[4] = uid->attrib_len;
356             gcry_md_write( md, buf, 5 );
357         }
358         gcry_md_write( md, uid->attrib_data, uid->attrib_len );
359     }
360     else {
361         if( sig->version >=4 ) {
362             byte buf[5];
363             buf[0] = 0xb4;            /* indicates a userid packet */
364             buf[1] = uid->len >> 24;  /* always use 4 length bytes */
365             buf[2] = uid->len >> 16;
366             buf[3] = uid->len >>  8;
367             buf[4] = uid->len;
368             gcry_md_write( md, buf, 5 );
369         }
370         gcry_md_write( md, uid->name, uid->len );
371     }
372 }
373
374 static void
375 cache_sig_result ( PKT_signature *sig, int result )
376 {
377     if ( !result ) {
378         sig->flags.checked = 1;
379         sig->flags.valid = 1;
380     }
381     else if ( gpg_err_code (result) == GPG_ERR_BAD_SIGNATURE ) {
382         sig->flags.checked = 1;
383         sig->flags.valid = 0;
384     }
385     else {
386         sig->flags.checked = 0;
387         sig->flags.valid = 0;
388     }
389 }
390
391 /* Check the revocation keys to see if any of them have revoked our
392    pk.  sig is the revocation sig.  pk is the key it is on.  This code
393    will need to be modified if gpg ever becomes multi-threaded.  Note
394    that this guarantees that a designated revocation sig will never be
395    considered valid unless it is actually valid, as well as being
396    issued by a revocation key in a valid direct signature.  Note also
397    that this is written so that a revoked revoker can still issue
398    revocations: i.e. If A revokes B, but A is revoked, B is still
399    revoked.  I'm not completely convinced this is the proper behavior,
400    but it matches how PGP does it. -dms */
401
402 /* Returns 0 if sig is valid (i.e. pk is revoked), non-0 if not
403    revoked.  It is important that G10ERR_NO_PUBKEY is only returned
404    when a revocation signature is from a valid revocation key
405    designated in a revkey subpacket, but the revocation key itself
406    isn't present. */
407 int
408 check_revocation_keys(PKT_public_key *pk,PKT_signature *sig)
409 {
410   static int busy=0;
411   int i,rc=G10ERR_GENERAL;
412
413   assert(IS_KEY_REV(sig));
414   assert((sig->keyid[0]!=pk->keyid[0]) || (sig->keyid[0]!=pk->keyid[1]));
415
416   if (busy)
417     {
418       /* Return an error (i.e. not revoked), but mark the pk as
419          uncacheable as we don't really know its revocation status
420          until it is checked directly.  */
421       pk->flags.dont_cache = 1;
422       return rc;
423     }
424
425   busy=1;
426
427   /*  printf("looking at %08lX with a sig from %08lX\n",(ulong)pk->keyid[1],
428       (ulong)sig->keyid[1]); */
429
430   /* is the issuer of the sig one of our revokers? */
431   if( !pk->revkey && pk->numrevkeys )
432      BUG();
433   else
434       for(i=0;i<pk->numrevkeys;i++)
435         {
436           u32 keyid[2];
437
438           keyid_from_fingerprint(pk->revkey[i].fpr,MAX_FINGERPRINT_LEN,keyid);
439
440           if(keyid[0]==sig->keyid[0] && keyid[1]==sig->keyid[1])
441             {
442               gcry_md_hd_t md;
443
444               if (gcry_md_open (&md, sig->digest_algo, 0))
445                 BUG ();
446               hash_public_key(md,pk);
447               rc=signature_check(sig,md);
448               cache_sig_result(sig,rc);
449               gcry_md_close (md);
450               break;
451             }
452         }
453
454   busy=0;
455
456   return rc;
457 }
458
459 /* Backsigs (0x19) have the same format as binding sigs (0x18), but
460    this function is simpler than check_key_signature in a few ways.
461    For example, there is no support for expiring backsigs since it is
462    questionable what such a thing actually means.  Note also that the
463    sig cache check here, unlike other sig caches in GnuPG, is not
464    persistent. */
465 int
466 check_backsig(PKT_public_key *main_pk,PKT_public_key *sub_pk,
467               PKT_signature *backsig)
468 {
469   gcry_md_hd_t md;
470   int rc;
471
472   /* Always check whether the algorithm is available.  Although
473      gcry_md_open woyuld throw an error, some libgcrypt versions will
474      print a debug message in that case too. */
475   if ((rc=openpgp_md_test_algo (backsig->digest_algo)))
476     return rc;
477
478   if(!opt.no_sig_cache && backsig->flags.checked)
479     return backsig->flags.valid? 0 : gpg_error (GPG_ERR_BAD_SIGNATURE);
480
481   rc = gcry_md_open (&md, backsig->digest_algo,0);
482   if (!rc)
483     {
484       hash_public_key(md,main_pk);
485       hash_public_key(md,sub_pk);
486       rc=do_check(sub_pk,backsig,md,NULL,NULL,NULL);
487       cache_sig_result(backsig,rc);
488       gcry_md_close(md);
489     }
490
491   return rc;
492 }
493
494
495 /****************
496  * check the signature pointed to by NODE. This is a key signature.
497  * If the function detects a self-signature, it uses the PK from
498  * ROOT and does not read any public key.
499  */
500 int
501 check_key_signature( KBNODE root, KBNODE node, int *is_selfsig )
502 {
503   return check_key_signature2(root, node, NULL, NULL, is_selfsig, NULL, NULL );
504 }
505
506 /* If check_pk is set, then use it to check the signature in node
507    rather than getting it from root or the keydb.  If ret_pk is set,
508    fill in the public key that was used to verify the signature.
509    ret_pk is only meaningful when the verification was successful. */
510 /* TODO: add r_revoked here as well.  It has the same problems as
511    r_expiredate and r_expired and the cache. */
512 int
513 check_key_signature2( KBNODE root, KBNODE node, PKT_public_key *check_pk,
514                       PKT_public_key *ret_pk, int *is_selfsig,
515                       u32 *r_expiredate, int *r_expired )
516 {
517     gcry_md_hd_t md;
518     PKT_public_key *pk;
519     PKT_signature *sig;
520     int algo;
521     int rc;
522
523     if( is_selfsig )
524         *is_selfsig = 0;
525     if( r_expiredate )
526         *r_expiredate = 0;
527     if( r_expired )
528         *r_expired = 0;
529     assert( node->pkt->pkttype == PKT_SIGNATURE );
530     assert( root->pkt->pkttype == PKT_PUBLIC_KEY );
531
532     pk = root->pkt->pkt.public_key;
533     sig = node->pkt->pkt.signature;
534     algo = sig->digest_algo;
535
536     /* Check whether we have cached the result of a previous signature
537        check.  Note that we may no longer have the pubkey or hash
538        needed to verify a sig, but can still use the cached value.  A
539        cache refresh detects and clears these cases. */
540     if ( !opt.no_sig_cache ) {
541         if (sig->flags.checked) { /*cached status available*/
542             if( is_selfsig ) {
543                 u32 keyid[2];
544
545                 keyid_from_pk( pk, keyid );
546                 if( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1] )
547                     *is_selfsig = 1;
548             }
549             /* BUG: This is wrong for non-self-sigs.. needs to be the
550                actual pk */
551             if((rc=do_check_messages(pk,sig,r_expired,NULL)))
552               return rc;
553             return sig->flags.valid? 0 : gpg_error (GPG_ERR_BAD_SIGNATURE);
554         }
555     }
556
557     if( (rc=openpgp_pk_test_algo(sig->pubkey_algo)) )
558         return rc;
559     if( (rc=openpgp_md_test_algo(algo)) )
560         return rc;
561
562     if( sig->sig_class == 0x20 ) { /* key revocation */
563         u32 keyid[2];
564         keyid_from_pk( pk, keyid );
565
566         /* is it a designated revoker? */
567         if(keyid[0]!=sig->keyid[0] || keyid[1]!=sig->keyid[1])
568           rc=check_revocation_keys(pk,sig);
569         else
570           {
571             if (gcry_md_open (&md, algo, 0 ))
572               BUG ();
573             hash_public_key( md, pk );
574             rc = do_check( pk, sig, md, r_expired, NULL, ret_pk );
575             cache_sig_result ( sig, rc );
576             gcry_md_close(md);
577           }
578     }
579     else if( sig->sig_class == 0x28 ) { /* subkey revocation */
580         KBNODE snode = find_prev_kbnode( root, node, PKT_PUBLIC_SUBKEY );
581
582         if( snode ) {
583             if (gcry_md_open (&md, algo, 0))
584               BUG ();
585             hash_public_key( md, pk );
586             hash_public_key( md, snode->pkt->pkt.public_key );
587             rc = do_check( pk, sig, md, r_expired, NULL, ret_pk );
588             cache_sig_result ( sig, rc );
589             gcry_md_close(md);
590         }
591         else
592           {
593             if (opt.verbose)
594               log_info (_("key %s: no subkey for subkey"
595                           " revocation signature\n"),keystr_from_pk(pk));
596             rc = G10ERR_SIG_CLASS;
597           }
598     }
599     else if( sig->sig_class == 0x18 ) { /* key binding */
600         KBNODE snode = find_prev_kbnode( root, node, PKT_PUBLIC_SUBKEY );
601
602         if( snode ) {
603             if( is_selfsig ) {  /* does this make sense????? */
604                 u32 keyid[2];   /* it should always be a selfsig */
605
606                 keyid_from_pk( pk, keyid );
607                 if( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1] )
608                     *is_selfsig = 1;
609             }
610             if (gcry_md_open (&md, algo, 0))
611               BUG ();
612             hash_public_key( md, pk );
613             hash_public_key( md, snode->pkt->pkt.public_key );
614             rc = do_check( pk, sig, md, r_expired, NULL, ret_pk );
615             cache_sig_result ( sig, rc );
616             gcry_md_close(md);
617         }
618         else
619           {
620             if (opt.verbose)
621               log_info(_("key %s: no subkey for subkey"
622                          " binding signature\n"),keystr_from_pk(pk));
623             rc = G10ERR_SIG_CLASS;
624           }
625     }
626     else if( sig->sig_class == 0x1f ) { /* direct key signature */
627         if (gcry_md_open (&md, algo, 0 ))
628           BUG ();
629         hash_public_key( md, pk );
630         rc = do_check( pk, sig, md, r_expired, NULL, ret_pk );
631         cache_sig_result ( sig, rc );
632         gcry_md_close(md);
633     }
634     else { /* all other classes */
635         KBNODE unode = find_prev_kbnode( root, node, PKT_USER_ID );
636
637         if( unode ) {
638             u32 keyid[2];
639
640             keyid_from_pk( pk, keyid );
641             if (gcry_md_open (&md, algo, 0 ))
642               BUG ();
643             hash_public_key( md, pk );
644             hash_uid_node( unode, md, sig );
645             if( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1] )
646               {
647                 if( is_selfsig )
648                   *is_selfsig = 1;
649                 rc = do_check( pk, sig, md, r_expired, NULL, ret_pk );
650               }
651             else if (check_pk)
652               rc=do_check(check_pk,sig,md,r_expired,NULL,ret_pk);
653             else
654               rc=signature_check2(sig,md,r_expiredate,r_expired,NULL,ret_pk);
655
656             cache_sig_result ( sig, rc );
657             gcry_md_close(md);
658         }
659         else
660           {
661             if (!opt.quiet)
662               log_info ("key %s: no user ID for key signature packet"
663                         " of class %02x\n",keystr_from_pk(pk),sig->sig_class);
664             rc = G10ERR_SIG_CLASS;
665           }
666     }
667
668     return rc;
669 }