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