41ac89341a5c6724d58bf1aede5bd48b2f5bea9c
[gnupg.git] / g10 / sig-check.c
1 /* sig-check.c -  Check a signature
2  *      Copyright (c) 1997 by Werner Koch (dd9jn)
3  *
4  * This file is part of G10.
5  *
6  * G10 is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * G10 is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <assert.h>
26 #include "util.h"
27 #include "packet.h"
28 #include "memory.h"
29 #include "mpi.h"
30 #include "keydb.h"
31 #include "cipher.h"
32
33
34 /****************
35  * Check the signature which is contained in the rsa_integer.
36  * The md5handle should be currently open, so that this function
37  * is able to append some data, before getting the digest.
38  */
39 int
40 signature_check( PKT_signature *sig, MD_HANDLE digest )
41 {
42     PKT_pubkey_cert *pkc = m_alloc_clear( sizeof *pkc );
43     MPI result = mpi_alloc(35);
44     int rc=0, i, j, c, old_enc;
45     byte *dp;
46
47
48     if( get_pubkey( pkc, sig->keyid ) ) {
49         rc = G10ERR_NO_PUBKEY;
50         goto leave;
51     }
52
53     if( pkc->pubkey_algo == PUBKEY_ALGO_RSA ) {
54         RSA_public_key pkey;
55         pkey.n = pkc->d.rsa.rsa_n;
56         pkey.e = pkc->d.rsa.rsa_e;
57         rsa_public( result, sig->d.rsa.rsa_integer, &pkey );
58     }
59     else {
60         log_debug("signature_check: unsupported pubkey algo %d\n",
61                         pkc->pubkey_algo );
62         rc = G10ERR_PUBKEY_ALGO;
63         goto leave;
64     }
65
66
67     /* Now RESULT contains the deciphered session key.
68      *
69      * The session key is stored in different ways:
70      *
71      * Old versions encodes the digest in in this format (msb is left):
72      *
73      *     0  1  MD5(16 bytes)  0  PAD(n bytes)  1
74      *
75      * Later versions encodes the digest like this:
76      *
77      *     0  1  PAD(n bytes)   0  ASN(18 bytes)  MD(16 bytes)
78      *
79      * RIPE MD 160 digests are encoded like this:
80      *
81      *     0  42 PAD(n bytes)   0  ASN(18 bytes)  MD(20 bytes)
82      *
83      * FIXME: we should use another ASN!
84      *
85      * PAD consists of FF bytes.
86      * ASN is here the constant: 3020300c06082a864886f70d020505000410
87      */
88     old_enc = 0;
89     for(i=j=0; (c=mpi_getbyte(result, i)) != -1; i++ ) {
90         if( !j ) {
91             if( !i && c != 1 )
92                 break;
93             else if( i && c == 0xff )
94                 ; /* skip the padding */
95             else if( i && !c )
96                 j++;
97             else
98                 break;
99         }
100         else if( ++j == 18 && c != 1 )
101             break;
102         else if( j == 19 && c == 0 ) {
103             old_enc++;
104             break;
105         }
106     }
107     if( old_enc ) {
108         log_error("old encoding scheme is not supported\n");
109         rc = G10ERR_GENERAL;
110         goto leave;
111     }
112
113     if( sig->d.rsa.digest_algo == DIGEST_ALGO_RMD160 ) {
114         static byte asn[18] = /* stored reverse FIXME: need other values*/
115               { 0x10, 0x04, 0x00, 0x05, 0x05, 0x02, 0x0d, 0xf7, 0x86,
116                 0x48, 0x86, 0x2a, 0x08, 0x06, 0x0c, 0x30, 0x20, 0x30 };
117
118         for(i=20,j=0; j < 18 && (c=mpi_getbyte(result, i)) != -1; i++, j++ )
119             if( asn[j] != c )
120                 break;
121         if( j != 18 ) { /* ASN is wrong */
122             rc = G10ERR_BAD_PUBKEY;
123             goto leave;
124         }
125         if( !c ) {
126             for(; (c=mpi_getbyte(result, i)) != -1; i++ )
127                 if( c != 0xff  )
128                     break;
129             if( c != 42 || mpi_getbyte(result, i) ) {
130                 /* Padding or leading bytes in signature is wrong */
131                 rc = G10ERR_BAD_PUBKEY;
132                 goto leave;
133             }
134             if( mpi_getbyte(result, 19) != sig->d.rsa.digest_start[0]
135                 || mpi_getbyte(result, 18) != sig->d.rsa.digest_start[1] ) {
136                 /* Wrong key used to check the signature */
137                 rc = G10ERR_BAD_PUBKEY;
138                 goto leave;
139             }
140         }
141
142         /* complete the digest */
143         rmd160_putchar( digest.u.rmd, sig->sig_class );
144         {   u32 a = sig->timestamp;
145             rmd160_putchar( digest.u.rmd, (a >> 24) & 0xff );
146             rmd160_putchar( digest.u.rmd, (a >> 16) & 0xff );
147             rmd160_putchar( digest.u.rmd, (a >>  8) & 0xff );
148             rmd160_putchar( digest.u.rmd,  a        & 0xff );
149         }
150         dp = rmd160_final( digest.u.rmd );
151         for(i=19; i >= 0; i--, dp++ )
152             if( mpi_getbyte( result, i ) != *dp ) {
153                 rc = G10ERR_BAD_SIGN;
154                 goto leave;
155             }
156     }
157     else if( sig->d.rsa.digest_algo == DIGEST_ALGO_MD5 ) {
158         static byte asn[18] = /* stored reverse */
159               { 0x10, 0x04, 0x00, 0x05, 0x05, 0x02, 0x0d, 0xf7, 0x86,
160                 0x48, 0x86, 0x2a, 0x08, 0x06, 0x0c, 0x30, 0x20, 0x30 };
161
162         for(i=16,j=0; j < 18 && (c=mpi_getbyte(result, i)) != -1; i++, j++ )
163             if( asn[j] != c )
164                 break;
165         if( j != 18 ) { /* ASN is wrong */
166             rc = G10ERR_BAD_PUBKEY;
167             goto leave;
168         }
169         if( !c ) {
170             for(; (c=mpi_getbyte(result, i)) != -1; i++ )
171                 if( c != 0xff  )
172                     break;
173             if( c != 1 || mpi_getbyte(result, i) ) {
174                 /* Padding or leading bytes in signature is wrong */
175                 rc = G10ERR_BAD_PUBKEY;
176                 goto leave;
177             }
178             if( mpi_getbyte(result, 15) != sig->d.rsa.digest_start[0]
179                 || mpi_getbyte(result, 14) != sig->d.rsa.digest_start[1] ) {
180                 /* Wrong key used to check the signature */
181                 rc = G10ERR_BAD_PUBKEY;
182                 goto leave;
183             }
184         }
185
186         /* complete the digest */
187         md5_putchar( digest.u.md5, sig->sig_class );
188         {   u32 a = sig->timestamp;
189             md5_putchar( digest.u.md5, (a >> 24) & 0xff );
190             md5_putchar( digest.u.md5, (a >> 16) & 0xff );
191             md5_putchar( digest.u.md5, (a >>  8) & 0xff );
192             md5_putchar( digest.u.md5,  a        & 0xff );
193         }
194         md5_final( digest.u.md5 );
195         dp = md5_read( digest.u.md5 );
196         for(i=15; i >= 0; i--, dp++ )
197             if( mpi_getbyte( result, i ) != *dp ) {
198                 rc = G10ERR_BAD_SIGN;
199                 goto leave;
200             }
201     }
202     else {
203         rc = G10ERR_DIGEST_ALGO;
204         goto leave;
205     }
206
207   leave:
208     mpi_free( result );
209     if( pkc )
210         free_pubkey_cert( pkc );
211     return rc;
212 }
213