a whole bunch of internal cleanups
[gnupg.git] / cipher / pubkey.c
1 /* pubkey.c  -  pubkey dispatcher
2  *      Copyright (C) 1998 Free Software Foundation, Inc.
3  *
4  * This file is part of GNUPG.
5  *
6  * GNUPG 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  * GNUPG 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 <errno.h>
26 #include <assert.h>
27 #include "util.h"
28 #include "errors.h"
29 #include "mpi.h"
30 #include "cipher.h"
31 #include "dynload.h"
32
33 /****************
34  * Return the number of public key material numbers
35  */
36 int
37 pubkey_get_npkey( int algo )
38 {
39     if( is_ELGAMAL(algo) )
40         return 3;
41     if( is_RSA(algo) )
42         return 2;
43     if( algo == PUBKEY_ALGO_DSA )
44         return 4;
45     return 0;
46 }
47
48 /****************
49  * Return the number of secret key material numbers
50  */
51 int
52 pubkey_get_nskey( int algo )
53 {
54     if( is_ELGAMAL(algo) )
55         return 4;
56     if( is_RSA(algo) )
57         return 6;
58     if( algo == PUBKEY_ALGO_DSA )
59         return 5;
60     return 0;
61 }
62
63 /****************
64  * Return the number of signature material numbers
65  */
66 int
67 pubkey_get_nsig( int algo )
68 {
69     if( is_ELGAMAL(algo) )
70         return 2;
71     if( is_RSA(algo) )
72         return 1;
73     if( algo == PUBKEY_ALGO_DSA )
74         return 2;
75     return 0;
76 }
77
78 /****************
79  * Return the number of encryption material numbers
80  */
81 int
82 pubkey_get_nenc( int algo )
83 {
84     if( is_ELGAMAL(algo) )
85         return 2;
86     if( is_RSA(algo) )
87         return 1;
88     return 0;
89 }
90
91 /****************
92  * Get the number of nbits from the public key
93  */
94 unsigned
95 pubkey_nbits( int algo, MPI *pkey )
96 {
97     if( is_ELGAMAL( algo ) )
98         return mpi_get_nbits( pkey[0] );
99
100     if( algo == PUBKEY_ALGO_DSA )
101         return mpi_get_nbits( pkey[0] );
102
103     if( is_RSA( algo) )
104         return mpi_get_nbits( pkey[0] );
105
106     return 0;
107 }
108
109
110 int
111 pubkey_check_secret_key( int algo, MPI *skey )
112 {
113     int rc = 0;
114
115     if( is_ELGAMAL(algo) ) {
116         ELG_secret_key sk;
117         sk.p = skey[0];
118         sk.g = skey[1];
119         sk.y = skey[2];
120         sk.x = skey[3];
121         if( !elg_check_secret_key( &sk ) )
122             rc = G10ERR_BAD_SECKEY;
123     }
124     else if( algo == PUBKEY_ALGO_DSA ) {
125         DSA_secret_key sk;
126         sk.p = skey[0];
127         sk.q = skey[1];
128         sk.g = skey[2];
129         sk.y = skey[3];
130         sk.x = skey[4];
131         if( !dsa_check_secret_key( &sk ) )
132             rc = G10ERR_BAD_SECKEY;
133     }
134  #ifdef HAVE_RSA_CIPHER
135     else if( is_RSA(k->pubkey_algo) ) {
136         /* FIXME */
137         RSA_secret_key sk;
138         assert( ndata == 1 && nskey == 6 );
139         sk.n = skey[0];
140         sk.e = skey[1];
141         sk.d = skey[2];
142         sk.p = skey[3];
143         sk.q = skey[4];
144         sk.u = skey[5];
145         plain = mpi_alloc_secure( mpi_get_nlimbs(sk.n) );
146         rsa_secret( plain, data[0], &sk );
147     }
148   #endif
149     else
150         rc = G10ERR_PUBKEY_ALGO;
151     return rc;
152 }
153
154
155 /****************
156  * This is the interface to the public key encryption.
157  * Encrypt DATA with PKEY and put it into RESARR which
158  * should be an array of MPIs of size PUBKEY_MAX_NENC (or less if the
159  * algorithm allows this - check with pubkey_get_nenc() )
160  */
161 int
162 pubkey_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey )
163 {
164     if( DBG_CIPHER ) {
165         int i;
166         log_debug("pubkey_encrypt: algo=%d\n", algo );
167         for(i=0; i < pubkey_get_npkey(algo); i++ )
168             log_mpidump("  pkey:", pkey[i] );
169         log_mpidump("  data:", data );
170     }
171     /* FIXME: check that data fits into the key */
172     if( is_ELGAMAL(algo) ) {
173         ELG_public_key pk;
174         pk.p = pkey[0];
175         pk.g = pkey[1];
176         pk.y = pkey[2];
177         resarr[0] = mpi_alloc( mpi_get_nlimbs( pk.p ) );
178         resarr[1] = mpi_alloc( mpi_get_nlimbs( pk.p ) );
179         elg_encrypt( resarr[0], resarr[1], data, &pk );
180     }
181  #ifdef HAVE_RSA_CIPHER
182     else if( algo == PUBKEY_ALGO_RSA || algo == PUBKEY_ALGO_RSA_E ) {
183         RSA_public_key pk;
184         pk.n = pkey[0];
185         pk.e = pkey[1];
186         resarr[0] = mpi_alloc( mpi_get_nlimbs( pk.p ) );
187         rsa_public( resarr[0], data, &pk );
188     }
189   #endif
190     else
191         return G10ERR_PUBKEY_ALGO;
192
193     if( DBG_CIPHER ) {
194         int i;
195         for(i=0; i < pubkey_get_nenc(algo); i++ )
196             log_mpidump("  encr:", resarr[i] );
197     }
198     return 0;
199 }
200
201
202
203 /****************
204  * This is the interface to the public key decryption.
205  * ALGO gives the algorithm to use and this implicitly determines
206  * the size of the arrays.
207  * result is a pointer to a mpi variable which will receive a
208  * newly allocated mpi or NULL in case of an error.
209  */
210 int
211 pubkey_decrypt( int algo, MPI *result, MPI *data, MPI *skey )
212 {
213     MPI plain = NULL;
214
215     *result = NULL; /* so the caller can always do an mpi_free */
216     if( DBG_CIPHER ) {
217         int i;
218         log_debug("pubkey_decrypt: algo=%d\n", algo );
219         for(i=0; i < pubkey_get_nskey(algo); i++ )
220             log_mpidump("  skey:", skey[i] );
221         for(i=0; i < pubkey_get_nenc(algo); i++ )
222             log_mpidump("  data:", data[i] );
223     }
224     if( is_ELGAMAL(algo) ) {
225         ELG_secret_key sk;
226         sk.p = skey[0];
227         sk.g = skey[1];
228         sk.y = skey[2];
229         sk.x = skey[3];
230         plain = mpi_alloc_secure( mpi_get_nlimbs( sk.p ) );
231         elg_decrypt( plain, data[0], data[1], &sk );
232     }
233  #ifdef HAVE_RSA_CIPHER
234     else if( algo == PUBKEY_ALGO_RSA || algo == PUBKEY_ALGO_RSA_E ) {
235         RSA_secret_key sk;
236         sk.n = skey[0];
237         sk.e = skey[1];
238         sk.d = skey[2];
239         sk.p = skey[3];
240         sk.q = skey[4];
241         sk.u = skey[5];
242         plain = mpi_alloc_secure( mpi_get_nlimbs(sk.n) );
243         rsa_secret( plain, data[0], &sk );
244     }
245   #endif
246     else
247         return G10ERR_PUBKEY_ALGO;
248
249     *result = plain;
250     return 0;
251 }
252
253
254 /****************
255  * This is the interface to the public key signing.
256  * Sign hash with skey and put the result into resarr which
257  * should be an array of MPIs of size PUBKEY_MAX_NSIG (or less if the
258  * algorithm allows this - check with pubkey_get_nsig() )
259  */
260 int
261 pubkey_sign( int algo, MPI *resarr, MPI data, MPI *skey )
262 {
263     if( DBG_CIPHER ) {
264         int i;
265         log_debug("pubkey_sign: algo=%d\n", algo );
266         for(i=0; i < pubkey_get_nskey(algo); i++ )
267             log_mpidump("  skey:", skey[i] );
268         log_mpidump("  data:", data );
269     }
270
271     if( is_ELGAMAL(algo) ) {
272         ELG_secret_key sk;
273         sk.p = skey[0];
274         sk.g = skey[1];
275         sk.y = skey[2];
276         sk.x = skey[3];
277         resarr[0] = mpi_alloc( mpi_get_nlimbs( sk.p ) );
278         resarr[1] = mpi_alloc( mpi_get_nlimbs( sk.p ) );
279         elg_sign( resarr[0], resarr[1], data, &sk );
280     }
281     else if( algo == PUBKEY_ALGO_DSA ) {
282         DSA_secret_key sk;
283         sk.p = skey[0];
284         sk.q = skey[1];
285         sk.g = skey[2];
286         sk.y = skey[3];
287         sk.x = skey[4];
288         resarr[0] = mpi_alloc( mpi_get_nlimbs( sk.p ) );
289         resarr[1] = mpi_alloc( mpi_get_nlimbs( sk.p ) );
290         dsa_sign( resarr[0], resarr[1], data, &sk );
291     }
292  #ifdef HAVE_RSA_CIPHER
293     else if( algo == PUBKEY_ALGO_RSA || algo == PUBKEY_ALGO_RSA_S ) {
294         RSA_secret_key sk;
295         sk.n = skey[0];
296         sk.e = skey[1];
297         sk.d = skey[2];
298         sk.p = skey[3];
299         sk.q = skey[4];
300         sk.u = skey[5];
301         plain = mpi_alloc_secure( mpi_get_nlimbs(sk.n) );
302         rsa_sign( plain, data[0], &sk );
303     }
304   #endif
305     else
306         return G10ERR_PUBKEY_ALGO;
307
308     if( DBG_CIPHER ) {
309         int i;
310         for(i=0; i < pubkey_get_nsig(algo); i++ )
311             log_mpidump("   sig:", resarr[i] );
312     }
313
314     return 0;
315 }
316
317 /****************
318  * Verify a public key signature.
319  * Return 0 if the signature is good
320  */
321 int
322 pubkey_verify( int algo, MPI hash, MPI *data, MPI *pkey )
323 {
324     int rc = 0;
325
326     if( is_ELGAMAL( algo ) ) {
327         ELG_public_key pk;
328         pk.p = pkey[0];
329         pk.g = pkey[1];
330         pk.y = pkey[2];
331         if( !elg_verify( data[0], data[1], hash, &pk ) )
332             rc = G10ERR_BAD_SIGN;
333     }
334     else if( algo == PUBKEY_ALGO_DSA ) {
335         DSA_public_key pk;
336         pk.p = pkey[0];
337         pk.q = pkey[1];
338         pk.g = pkey[2];
339         pk.y = pkey[3];
340         if( !dsa_verify( data[0], data[1], hash, &pk ) )
341             rc = G10ERR_BAD_SIGN;
342     }
343  #ifdef HAVE_RSA_CIPHER
344     else if( algo == PUBKEY_ALGO_RSA || algo == PUBKEY_ALGO_RSA_S ) {
345         RSA_public_key pk;
346         int i, j, c, old_enc;
347         byte *dp;
348         const byte *asn;
349         size_t mdlen, asnlen;
350
351         pk.e = pkey[0];
352         pk.n = pkey[1];
353         result = mpi_alloc(40);
354         rsa_public( result, data[0], &pk );
355
356         old_enc = 0;
357         for(i=j=0; (c=mpi_getbyte(result, i)) != -1; i++ ) {
358             if( !j ) {
359                 if( !i && c != 1 )
360                     break;
361                 else if( i && c == 0xff )
362                     ; /* skip the padding */
363                 else if( i && !c )
364                     j++;
365                 else
366                     break;
367             }
368             else if( ++j == 18 && c != 1 )
369                 break;
370             else if( j == 19 && c == 0 ) {
371                 old_enc++;
372                 break;
373             }
374         }
375         if( old_enc ) {
376             log_error("old encoding scheme is not supported\n");
377             rc = G10ERR_GENERAL;
378             goto leave;
379         }
380
381         if( (rc=check_digest_algo(sig->digest_algo)) )
382             goto leave; /* unsupported algo */
383         md_enable( digest, sig->digest_algo );
384         asn = md_asn_oid( sig->digest_algo, &asnlen, &mdlen );
385
386         for(i=mdlen,j=asnlen-1; (c=mpi_getbyte(result, i)) != -1 && j >= 0;
387                                                                i++, j-- )
388             if( asn[j] != c )
389                 break;
390         if( j != -1 || mpi_getbyte(result, i) ) { /* ASN is wrong */
391             rc = G10ERR_BAD_PUBKEY;
392             goto leave;
393         }
394         for(i++; (c=mpi_getbyte(result, i)) != -1; i++ )
395             if( c != 0xff  )
396                 break;
397         i++;
398         if( c != sig->digest_algo || mpi_getbyte(result, i) ) {
399             /* Padding or leading bytes in signature is wrong */
400             rc = G10ERR_BAD_PUBKEY;
401             goto leave;
402         }
403         if( mpi_getbyte(result, mdlen-1) != sig->digest_start[0]
404             || mpi_getbyte(result, mdlen-2) != sig->digest_start[1] ) {
405             /* Wrong key used to check the signature */
406             rc = G10ERR_BAD_PUBKEY;
407             goto leave;
408         }
409
410         /* complete the digest */
411         md_putc( digest, sig->sig_class );
412         {   u32 a = sig->timestamp;
413             md_putc( digest, (a >> 24) & 0xff );
414             md_putc( digest, (a >> 16) & 0xff );
415             md_putc( digest, (a >>  8) & 0xff );
416             md_putc( digest,  a        & 0xff );
417         }
418         md_final( digest );
419         dp = md_read( digest, sig->digest_algo );
420         for(i=mdlen-1; i >= 0; i--, dp++ ) {
421             if( mpi_getbyte( result, i ) != *dp ) {
422                 rc = G10ERR_BAD_SIGN;
423                 break;
424             }
425         }
426     }
427   #endif
428     else
429         rc = G10ERR_PUBKEY_ALGO;
430
431     return rc;
432 }
433