partial DSA support
[gnupg.git] / g10 / seckey-cert.c
1 /* seckey-cert.c -  secret key certifucate packet handling
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 <assert.h>
26 #include "util.h"
27 #include "memory.h"
28 #include "packet.h"
29 #include "mpi.h"
30 #include "keydb.h"
31 #include "cipher.h"
32
33 #if  BLOWFISH_BLOCKSIZE != 8
34   #error unsupportted blocksize
35 #endif
36
37 static u16
38 checksum_u16( unsigned n )
39 {
40     u16 a;
41
42     a  = (n >> 8) & 0xff;
43     a |= n & 0xff;
44     return a;
45 }
46
47 static u16
48 checksum( byte *p, unsigned n )
49 {
50     u16 a;
51
52     for(a=0; n; n-- )
53         a += *p++;
54     return a;
55 }
56
57
58
59 static int
60 check_elg( PKT_secret_cert *cert )
61 {
62     byte *buffer;
63     u16 csum=0;
64     int res;
65     unsigned nbytes;
66     u32 keyid[2];
67     ELG_secret_key skey;
68     char save_iv[8];
69
70     if( cert->d.elg.is_protected ) { /* remove the protection */
71         DEK *dek = NULL;
72         MPI test_x;
73         BLOWFISH_context *blowfish_ctx=NULL;
74
75         switch( cert->d.elg.protect.algo ) {
76           case CIPHER_ALGO_NONE: BUG(); break;
77           case CIPHER_ALGO_BLOWFISH:
78             keyid_from_skc( cert, keyid );
79             if( cert->d.elg.protect.s2k == 1
80                 || cert->d.elg.protect.s2k == 3 )
81                 dek = get_passphrase_hash( keyid, NULL,
82                                                  cert->d.elg.protect.salt );
83             else
84                 dek = get_passphrase_hash( keyid, NULL, NULL );
85
86             blowfish_ctx = m_alloc_secure( sizeof *blowfish_ctx );
87             blowfish_setkey( blowfish_ctx, dek->key, dek->keylen );
88             m_free(dek); /* pw is in secure memory, so m_free() burns it */
89             blowfish_setiv( blowfish_ctx, NULL );
90             memcpy(save_iv, cert->d.elg.protect.iv, 8 );
91             blowfish_decode_cfb( blowfish_ctx,
92                                  cert->d.elg.protect.iv,
93                                  cert->d.elg.protect.iv, 8 );
94             mpi_set_secure(cert->d.elg.x );
95             /*fixme: maybe it is better to set the buffer secure with a
96              * new get_buffer_secure() function */
97             buffer = mpi_get_buffer( cert->d.elg.x, &nbytes, NULL );
98             csum = checksum_u16( nbytes*8 );
99             blowfish_decode_cfb( blowfish_ctx, buffer, buffer, nbytes );
100             csum += checksum( buffer, nbytes );
101             test_x = mpi_alloc_secure( mpi_get_nlimbs(cert->d.elg.x) );
102             mpi_set_buffer( test_x, buffer, nbytes, 0 );
103             m_free( buffer );
104             m_free( blowfish_ctx );
105             /* now let's see wether we have used the right passphrase */
106             if( csum != cert->d.elg.csum ) {
107                 mpi_free(test_x);
108                 memcpy( cert->d.elg.protect.iv, save_iv, 8 );
109                 return G10ERR_BAD_PASS;
110             }
111
112             skey.p = cert->d.elg.p;
113             skey.g = cert->d.elg.g;
114             skey.y = cert->d.elg.y;
115             skey.x = test_x;
116             res = elg_check_secret_key( &skey );
117             memset( &skey, 0, sizeof skey );
118             if( !res ) {
119                 mpi_free(test_x);
120                 memcpy( cert->d.elg.protect.iv, save_iv, 8 );
121                 return G10ERR_BAD_PASS;
122             }
123             mpi_set(cert->d.elg.x, test_x);
124             mpi_free(test_x);
125             cert->d.elg.is_protected = 0;
126             break;
127
128           default:
129             return G10ERR_CIPHER_ALGO; /* unsupport protection algorithm */
130         }
131     }
132     else { /* not protected */
133         buffer = mpi_get_buffer( cert->d.elg.x, &nbytes, NULL );
134         csum = checksum_u16( nbytes*8 );
135         csum += checksum( buffer, nbytes );
136         m_free( buffer );
137         if( csum != cert->d.elg.csum )
138             return G10ERR_CHECKSUM;
139     }
140
141     return 0;
142 }
143
144
145 static int
146 protect_elg( PKT_secret_cert *cert, DEK *dek )
147 {
148     byte *buffer;
149     unsigned nbytes;
150
151     if( !cert->d.elg.is_protected ) { /* add the protection */
152         BLOWFISH_context *blowfish_ctx=NULL;
153
154         switch( cert->d.elg.protect.algo ) {
155           case CIPHER_ALGO_NONE: BUG(); break;
156           case CIPHER_ALGO_BLOWFISH:
157             blowfish_ctx = m_alloc_secure( sizeof *blowfish_ctx );
158             blowfish_setkey( blowfish_ctx, dek->key, dek->keylen );
159             blowfish_setiv( blowfish_ctx, NULL );
160             blowfish_encode_cfb( blowfish_ctx,
161                                  cert->d.elg.protect.iv,
162                                  cert->d.elg.protect.iv, 8 );
163             buffer = mpi_get_buffer( cert->d.elg.x, &nbytes, NULL );
164             blowfish_encode_cfb( blowfish_ctx, buffer, buffer, nbytes );
165             mpi_set_buffer( cert->d.elg.x, buffer, nbytes, 0 );
166             m_free( buffer );
167             m_free( blowfish_ctx );
168             cert->d.elg.is_protected = 1;
169             break;
170
171           default:
172             return G10ERR_CIPHER_ALGO; /* unsupport protection algorithm */
173         }
174     }
175     return 0;
176 }
177
178 static int
179 check_dsa( PKT_secret_cert *cert )
180 {
181     byte *buffer;
182     u16 csum=0;
183     int res;
184     unsigned nbytes;
185     u32 keyid[2];
186     DSA_secret_key skey;
187     char save_iv[8];
188
189     if( cert->d.dsa.is_protected ) { /* remove the protection */
190         DEK *dek = NULL;
191         MPI test_x;
192         BLOWFISH_context *blowfish_ctx=NULL;
193
194         switch( cert->d.dsa.protect.algo ) {
195           case CIPHER_ALGO_NONE: BUG(); break;
196           case CIPHER_ALGO_BLOWFISH:
197             keyid_from_skc( cert, keyid );
198             if( cert->d.dsa.protect.s2k == 1
199                 || cert->d.dsa.protect.s2k == 3 )
200                 dek = get_passphrase_hash( keyid, NULL,
201                                                  cert->d.dsa.protect.salt );
202             else
203                 dek = get_passphrase_hash( keyid, NULL, NULL );
204
205             blowfish_ctx = m_alloc_secure( sizeof *blowfish_ctx );
206             blowfish_setkey( blowfish_ctx, dek->key, dek->keylen );
207             m_free(dek); /* pw is in secure memory, so m_free() burns it */
208             blowfish_setiv( blowfish_ctx, NULL );
209             memcpy(save_iv, cert->d.dsa.protect.iv, 8 );
210             blowfish_decode_cfb( blowfish_ctx,
211                                  cert->d.dsa.protect.iv,
212                                  cert->d.dsa.protect.iv, 8 );
213             mpi_set_secure(cert->d.dsa.x );
214             /*fixme: maybe it is better to set the buffer secure with a
215              * new get_buffer_secure() function */
216             buffer = mpi_get_buffer( cert->d.dsa.x, &nbytes, NULL );
217             csum = checksum_u16( nbytes*8 );
218             blowfish_decode_cfb( blowfish_ctx, buffer, buffer, nbytes );
219             csum += checksum( buffer, nbytes );
220             test_x = mpi_alloc_secure( mpi_get_nlimbs(cert->d.dsa.x) );
221             mpi_set_buffer( test_x, buffer, nbytes, 0 );
222             m_free( buffer );
223             m_free( blowfish_ctx );
224             /* now let's see wether we have used the right passphrase */
225             if( csum != cert->d.dsa.csum ) {
226                 mpi_free(test_x);
227                 memcpy( cert->d.dsa.protect.iv, save_iv, 8 );
228                 return G10ERR_BAD_PASS;
229             }
230
231             skey.p = cert->d.dsa.p;
232             skey.q = cert->d.dsa.q;
233             skey.g = cert->d.dsa.g;
234             skey.y = cert->d.dsa.y;
235             skey.x = test_x;
236             res = dsa_check_secret_key( &skey );
237             memset( &skey, 0, sizeof skey );
238             if( !res ) {
239                 mpi_free(test_x);
240                 memcpy( cert->d.dsa.protect.iv, save_iv, 8 );
241                 return G10ERR_BAD_PASS;
242             }
243             mpi_set(cert->d.dsa.x, test_x);
244             mpi_free(test_x);
245             cert->d.dsa.is_protected = 0;
246             break;
247
248           default:
249             return G10ERR_CIPHER_ALGO; /* unsupport protection algorithm */
250         }
251     }
252     else { /* not protected */
253         buffer = mpi_get_buffer( cert->d.dsa.x, &nbytes, NULL );
254         csum = checksum_u16( nbytes*8 );
255         csum += checksum( buffer, nbytes );
256         m_free( buffer );
257         if( csum != cert->d.dsa.csum )
258             return G10ERR_CHECKSUM;
259     }
260
261     return 0;
262 }
263
264
265 static int
266 protect_dsa( PKT_secret_cert *cert, DEK *dek )
267 {
268     byte *buffer;
269     unsigned nbytes;
270
271     if( !cert->d.dsa.is_protected ) { /* add the protection */
272         BLOWFISH_context *blowfish_ctx=NULL;
273
274         switch( cert->d.dsa.protect.algo ) {
275           case CIPHER_ALGO_NONE: BUG(); break;
276           case CIPHER_ALGO_BLOWFISH:
277             blowfish_ctx = m_alloc_secure( sizeof *blowfish_ctx );
278             blowfish_setkey( blowfish_ctx, dek->key, dek->keylen );
279             blowfish_setiv( blowfish_ctx, NULL );
280             blowfish_encode_cfb( blowfish_ctx,
281                                  cert->d.dsa.protect.iv,
282                                  cert->d.dsa.protect.iv, 8 );
283             buffer = mpi_get_buffer( cert->d.dsa.x, &nbytes, NULL );
284             blowfish_encode_cfb( blowfish_ctx, buffer, buffer, nbytes );
285             mpi_set_buffer( cert->d.dsa.x, buffer, nbytes, 0 );
286             m_free( buffer );
287             m_free( blowfish_ctx );
288             cert->d.dsa.is_protected = 1;
289             break;
290
291           default:
292             return G10ERR_CIPHER_ALGO; /* unsupport protection algorithm */
293         }
294     }
295     return 0;
296 }
297
298
299 #ifdef HAVE_RSA_CIPHER
300 static int
301 check_rsa( PKT_secret_cert *cert )
302 {
303     byte *buffer;
304     u16 csum=0;
305     int res;
306     unsigned nbytes;
307     u32 keyid[2];
308     RSA_secret_key skey;
309
310     if( cert->d.rsa.is_protected ) { /* remove the protection */
311         DEK *dek = NULL;
312         BLOWFISH_context *blowfish_ctx=NULL;
313
314         switch( cert->d.rsa.protect_algo ) {
315             /* FIXME: use test variables to check for the correct key */
316           case CIPHER_ALGO_NONE: BUG(); break;
317           case CIPHER_ALGO_BLOWFISH:
318             keyid_from_skc( cert, keyid );
319             dek = get_passphrase_hash( keyid, NULL, NULL );
320             blowfish_ctx = m_alloc_secure( sizeof *blowfish_ctx );
321             blowfish_setkey( blowfish_ctx, dek->key, dek->keylen );
322             m_free(dek); /* pw is in secure memory, so m_free() burns it */
323             blowfish_setiv( blowfish_ctx, NULL );
324             blowfish_decode_cfb( blowfish_ctx,
325                                  cert->d.rsa.protect.blowfish.iv,
326                                  cert->d.rsa.protect.blowfish.iv, 8 );
327             csum = 0;
328             #define X(a) do { \
329                 mpi_set_secure(cert->d.rsa.rsa_##a); \
330                 buffer = mpi_get_buffer( cert->d.rsa.rsa_##a, &nbytes, NULL );\
331                 csum += checksum_u16( nbytes*8 );                            \
332                 blowfish_decode_cfb( blowfish_ctx, buffer, buffer, nbytes ); \
333                 csum += checksum( buffer, nbytes );                          \
334                 mpi_set_buffer(cert->d.rsa.rsa_##a, buffer, nbytes, 0 );     \
335                 m_free( buffer );                                            \
336                } while(0)
337             X(d);
338             X(p);
339             X(q);
340             X(u);
341             #undef X
342             cert->d.rsa.is_protected = 0;
343             m_free( blowfish_ctx );
344             /* now let's see wether we have used the right passphrase */
345             if( csum != cert->d.rsa.csum )
346                 return G10ERR_BAD_PASS;
347
348             skey.d = cert->d.rsa.rsa_d;
349             skey.p = cert->d.rsa.rsa_p;
350             skey.q = cert->d.rsa.rsa_q;
351             skey.u = cert->d.rsa.rsa_u;
352             res = rsa_check_secret_key( &skey );
353             memset( &skey, 0, sizeof skey );
354             if( !res )
355                 return G10ERR_BAD_PASS;
356             break;
357
358           default:
359             return G10ERR_CIPHER_ALGO; /* unsupported protection algorithm */
360         }
361     }
362     else { /* not protected */
363         csum =0;
364         buffer = mpi_get_buffer( cert->d.rsa.rsa_d, &nbytes, NULL );
365         csum += checksum_u16( nbytes*8 );
366         csum += checksum( buffer, nbytes );
367         m_free( buffer );
368         buffer = mpi_get_buffer( cert->d.rsa.rsa_p, &nbytes, NULL );
369         csum += checksum_u16( nbytes*8 );
370         csum += checksum( buffer, nbytes );
371         m_free( buffer );
372         buffer = mpi_get_buffer( cert->d.rsa.rsa_q, &nbytes, NULL );
373         csum += checksum_u16( nbytes*8 );
374         csum += checksum( buffer, nbytes );
375         m_free( buffer );
376         buffer = mpi_get_buffer( cert->d.rsa.rsa_u, &nbytes, NULL );
377         csum += checksum_u16( nbytes*8 );
378         csum += checksum( buffer, nbytes );
379         m_free( buffer );
380         if( csum != cert->d.rsa.csum )
381             return G10ERR_CHECKSUM;
382     }
383
384     return 0;
385 }
386 #endif /*HAVE_RSA_CIPHER*/
387
388
389
390
391 /****************
392  * Check the secret key certificate
393  * Ask up to 3 time for a correct passphrase
394  */
395 int
396 check_secret_key( PKT_secret_cert *cert )
397 {
398     int rc = G10ERR_BAD_PASS;
399     int i;
400
401     for(i=0; i < 3 && rc == G10ERR_BAD_PASS; i++ ) {
402         if( i )
403             log_error("Invalid passphrase; please try again ...\n");
404         if( cert->pubkey_algo == PUBKEY_ALGO_ELGAMAL )
405             rc = check_elg( cert );
406         else if( cert->pubkey_algo == PUBKEY_ALGO_DSA )
407             rc = check_dsa( cert );
408       #ifdef HAVE_RSA_CIPHER
409         else if( cert->pubkey_algo == PUBKEY_ALGO_RSA )
410             rc = check_rsa( cert );
411       #endif
412         else
413             rc = G10ERR_PUBKEY_ALGO;
414         if( get_passphrase_fd() != -1 )
415             break;
416     }
417     return rc;
418 }
419
420 /****************
421  * check wether the secret key is protected.
422  * Returns: 0 not protected, -1 on error or the protection algorithm
423  */
424 int
425 is_secret_key_protected( PKT_secret_cert *cert )
426 {
427     if( cert->pubkey_algo == PUBKEY_ALGO_ELGAMAL )
428         return cert->d.elg.is_protected? cert->d.elg.protect.algo : 0;
429     else if( cert->pubkey_algo == PUBKEY_ALGO_DSA )
430         return cert->d.dsa.is_protected? cert->d.dsa.protect.algo : 0;
431   #ifdef HAVE_RSA_CIPHER
432     else if( cert->pubkey_algo == PUBKEY_ALGO_RSA )
433         return cert->d.rsa.is_protected? cert->d.rsa.protect_algo : 0;
434   #endif
435     else
436         return -1; /* unsupported */
437 }
438
439
440 /****************
441  * Protect the secret key certificate with the passphrase from DEK
442  */
443 int
444 protect_secret_key( PKT_secret_cert *cert, DEK *dek )
445 {
446     if( !dek )
447         return 0;
448
449     if( cert->pubkey_algo == PUBKEY_ALGO_ELGAMAL )
450         return protect_elg( cert, dek );
451     else if( cert->pubkey_algo == PUBKEY_ALGO_DSA )
452         return protect_dsa( cert, dek );
453     else
454         return G10ERR_PUBKEY_ALGO;
455 }
456