3373bd35ed0a90d670fac9916158456ff05f74df
[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 #include "i18n.h"
35
36
37 static int
38 do_check( PKT_secret_cert *cert )
39 {
40     byte *buffer;
41     u16 csum=0;
42     int res;
43     unsigned nbytes;
44
45     if( cert->is_protected ) { /* remove the protection */
46         DEK *dek = NULL;
47         u32 keyid[2];
48         CIPHER_HANDLE cipher_hd=NULL;
49         PKT_secret_cert *save_cert;
50         char save_iv[8];
51
52         if( cert->protect.algo == CIPHER_ALGO_NONE )
53             BUG();
54         if( check_cipher_algo( cert->protect.algo ) )
55             return G10ERR_CIPHER_ALGO; /* unsupported protection algorithm */
56         keyid_from_skc( cert, keyid );
57         dek = passphrase_to_dek( keyid, cert->protect.algo,
58                                  &cert->protect.s2k, 0 );
59         cipher_hd = cipher_open( cert->protect.algo,
60                                  CIPHER_MODE_AUTO_CFB, 1);
61         cipher_setkey( cipher_hd, dek->key, dek->keylen );
62         cipher_setiv( cipher_hd, NULL );
63         m_free(dek); /* pw is in secure memory, so m_free() burns it */
64         save_cert = copy_secret_cert( NULL, cert );
65         memcpy(save_iv, cert->protect.iv, 8 );
66         cipher_decrypt( cipher_hd, cert->protect.iv, cert->protect.iv, 8 );
67         switch( cert->pubkey_algo ) {
68           case PUBKEY_ALGO_ELGAMAL:
69           case PUBKEY_ALGO_ELGAMAL_E:
70             buffer = mpi_get_secure_buffer( cert->d.elg.x, &nbytes, NULL );
71             cipher_decrypt( cipher_hd, buffer, buffer, nbytes );
72             mpi_set_buffer( cert->d.elg.x, buffer, nbytes, 0 );
73             csum = checksum_mpi( cert->d.elg.x );
74             m_free( buffer );
75             break;
76           case PUBKEY_ALGO_DSA:
77             buffer = mpi_get_secure_buffer( cert->d.dsa.x, &nbytes, NULL );
78             cipher_decrypt( cipher_hd, buffer, buffer, nbytes );
79             mpi_set_buffer( cert->d.dsa.x, buffer, nbytes, 0 );
80             csum = checksum_mpi( cert->d.dsa.x );
81             m_free( buffer );
82             break;
83         #ifdef HAVE_RSA_CIPHER
84           case PUBKEY_ALGO_RSA:
85           case PUBKEY_ALGO_RSA_E:
86           case PUBKEY_ALGO_RSA_S:
87             csum = 0;
88             #define X(a) do { \
89                 buffer = mpi_get_secure_buffer( cert->d.rsa.##a,     \
90                                                 &nbytes, NULL );     \
91                 csum += checksum_u16( nbytes*8 );                    \
92                 cipher_decrypt( cipher_hd, buffer, buffer, nbytes ); \
93                 csum += checksum( buffer, nbytes );                  \
94                 mpi_set_buffer(cert->d.rsa.##a, buffer, nbytes, 0 ); \
95                 m_free( buffer );                                    \
96                } while(0)
97             X(d);
98             X(p);
99             X(q);
100             X(u);
101             #undef X
102             break;
103         #endif /* HAVE_RSA_CIPHER */
104
105           default: BUG();
106         }
107         cipher_close( cipher_hd );
108         /* now let's see whether we have used the right passphrase */
109         if( csum != cert->csum ) {
110             if( cert->pubkey_algo == PUBKEY_ALGO_ELGAMAL_E ) {
111                 /* very bad kludge to work around an early bug */
112                 csum -= checksum_u16( mpi_get_nbits(cert->d.elg.x) );
113                 nbytes = mpi_get_nlimbs(cert->d.elg.x) * 4;
114                 csum += checksum_u16( nbytes*8 );
115                 if( !opt.batch && csum == cert->csum )
116                     log_info("Probably you have an old key - use "
117                          "\"--change-passphrase\" to convert.\n");
118             }
119             if( csum != cert->csum ) {
120                 copy_secret_cert( cert, save_cert );
121                 free_secret_cert( save_cert );
122                 memcpy( cert->protect.iv, save_iv, 8 );
123                 return G10ERR_BAD_PASS;
124             }
125         }
126
127         switch( cert->pubkey_algo ) {
128           case PUBKEY_ALGO_ELGAMAL_E:
129           case PUBKEY_ALGO_ELGAMAL:
130             res = elg_check_secret_key( &cert->d.elg );
131             break;
132           case PUBKEY_ALGO_DSA:
133             res = dsa_check_secret_key( &cert->d.dsa );
134             break;
135         #ifdef HAVE_RSA_CIPHER
136           case PUBKEY_ALGO_RSA:
137           case PUBKEY_ALGO_RSA_E:
138           case PUBKEY_ALGO_RSA_S:
139             res = rsa_check_secret_key( &cert->d.rsa );
140             break;
141         #endif
142           default: BUG();
143         }
144         if( !res ) {
145             copy_secret_cert( cert, save_cert );
146             free_secret_cert( save_cert );
147             memcpy( cert->protect.iv, save_iv, 8 );
148             return G10ERR_BAD_PASS;
149         }
150         free_secret_cert( save_cert );
151         cert->is_protected = 0;
152     }
153     else { /* not protected */
154         switch( cert->pubkey_algo ) {
155           case PUBKEY_ALGO_ELGAMAL_E:
156           case PUBKEY_ALGO_ELGAMAL:
157             csum = checksum_mpi( cert->d.elg.x );
158             break;
159           case PUBKEY_ALGO_DSA:
160             csum = checksum_mpi( cert->d.dsa.x );
161             break;
162         #ifdef HAVE_RSA_CIPHER
163           case PUBKEY_ALGO_RSA_E:
164           case PUBKEY_ALGO_RSA_S:
165           case PUBKEY_ALGO_RSA:
166             csum =0;
167             buffer = mpi_get_buffer( cert->d.rsa.rsa_d, &nbytes, NULL );
168             csum += checksum_u16( nbytes*8 );
169             csum += checksum( buffer, nbytes );
170             m_free( buffer );
171             buffer = mpi_get_buffer( cert->d.rsa.rsa_p, &nbytes, NULL );
172             csum += checksum_u16( nbytes*8 );
173             csum += checksum( buffer, nbytes );
174             m_free( buffer );
175             buffer = mpi_get_buffer( cert->d.rsa.rsa_q, &nbytes, NULL );
176             csum += checksum_u16( nbytes*8 );
177             csum += checksum( buffer, nbytes );
178             m_free( buffer );
179             buffer = mpi_get_buffer( cert->d.rsa.rsa_u, &nbytes, NULL );
180             csum += checksum_u16( nbytes*8 );
181             csum += checksum( buffer, nbytes );
182             m_free( buffer );
183             break;
184         #endif
185           default: BUG();
186         }
187         if( csum != cert->csum ) {
188             if( cert->pubkey_algo == PUBKEY_ALGO_ELGAMAL_E ) {
189                 /* very bad kludge to work around an early bug */
190                 csum -= checksum_u16( mpi_get_nbits(cert->d.elg.x) );
191                 nbytes = mpi_get_nlimbs(cert->d.elg.x) * 4;
192                 csum += checksum_u16( nbytes*8 );
193                 if( !opt.batch && csum == cert->csum )
194                     log_info("Probably you have an old key - use "
195                          "\"--change-passphrase\" to convert.\n");
196             }
197             if( csum != cert->csum )
198                 return G10ERR_CHECKSUM;
199         }
200     }
201
202     return 0;
203 }
204
205
206
207 /****************
208  * Check the secret key certificate
209  * Ask up to 3 times for a correct passphrase
210  */
211 int
212 check_secret_key( PKT_secret_cert *cert )
213 {
214     int rc = G10ERR_BAD_PASS;
215     int i;
216
217     for(i=0; i < 3 && rc == G10ERR_BAD_PASS; i++ ) {
218         if( i )
219             log_error(_("Invalid passphrase; please try again ...\n"));
220         switch( cert->pubkey_algo ) {
221           case PUBKEY_ALGO_ELGAMAL_E:
222           case PUBKEY_ALGO_ELGAMAL:
223           case PUBKEY_ALGO_DSA:
224             rc = do_check( cert );
225           #if 0 /* set to 1 to enable the workaround */
226             if( rc == G10ERR_BAD_PASS && cert->is_protected
227                 && cert->protect.algo == CIPHER_ALGO_BLOWFISH
228                 && cert->pubkey_algo != PUBKEY_ALGO_ELGAMAL ) {
229                 /* Workaround for a bug in 0.2.16 which still used
230                  * a 160 bit key for BLOWFISH. */
231      log_info("trying workaround for 0.2.16 passphrase bug ...\n");
232      log_info("If you don't need this, uncomment it in g10/seckey-cert.c\n\n");
233                 cert->protect.algo = CIPHER_ALGO_BLOWFISH160;
234                 rc = do_check( cert );
235                 if( rc )
236                     rc = G10ERR_BAD_PASS;
237                 cert->protect.algo = CIPHER_ALGO_BLOWFISH;
238             }
239           #endif
240             break;
241         #ifdef HAVE_RSA_CIPHER
242           case PUBKEY_ALGO_RSA:
243           case PUBKEY_ALGO_RSA_E:
244           case PUBKEY_ALGO_RSA_S:
245             rc = do_check( cert );
246             break;
247         #endif
248           default: rc = G10ERR_PUBKEY_ALGO;
249         }
250         if( get_passphrase_fd() != -1 )
251             break;
252     }
253
254     return rc;
255 }
256
257 /****************
258  * check whether the secret key is protected.
259  * Returns: 0 not protected, -1 on error or the protection algorithm
260  */
261 int
262 is_secret_key_protected( PKT_secret_cert *cert )
263 {
264     return cert->is_protected? cert->protect.algo : 0;
265 }
266
267
268 static int
269 do_protect( void (*fnc)(CIPHER_HANDLE, byte *, byte *, unsigned),
270             CIPHER_HANDLE fnc_hd, PKT_secret_cert *cert )
271 {
272     byte *buffer;
273     unsigned nbytes;
274
275     switch( cert->pubkey_algo ) {
276       case PUBKEY_ALGO_ELGAMAL_E:
277         /* recalculate the checksum, so that --change-passphrase
278          * can be used to convert from the faulty to the correct one
279          * wk 06.04.98:
280          * fixme: remove this some time in the future.
281          */
282         cert->csum = checksum_mpi( cert->d.elg.x );
283       case PUBKEY_ALGO_ELGAMAL:
284         buffer = mpi_get_buffer( cert->d.elg.x, &nbytes, NULL );
285         (*fnc)( fnc_hd, buffer, buffer, nbytes );
286         mpi_set_buffer( cert->d.elg.x, buffer, nbytes, 0 );
287         m_free( buffer );
288         break;
289
290       case PUBKEY_ALGO_DSA:
291         buffer = mpi_get_buffer( cert->d.dsa.x, &nbytes, NULL );
292         (*fnc)( fnc_hd, buffer, buffer, nbytes );
293         mpi_set_buffer( cert->d.dsa.x, buffer, nbytes, 0 );
294         m_free( buffer );
295         break;
296
297       default: return G10ERR_PUBKEY_ALGO;
298     }
299     return 0;
300 }
301
302
303 /****************
304  * Protect the secret key certificate with the passphrase from DEK
305  */
306 int
307 protect_secret_key( PKT_secret_cert *cert, DEK *dek )
308 {
309     int rc=0;
310
311     if( !dek )
312         return 0;
313
314     if( !cert->is_protected ) { /* okay, apply the protection */
315         CIPHER_HANDLE cipher_hd=NULL;
316
317         if( check_cipher_algo( cert->protect.algo ) )
318             rc = G10ERR_CIPHER_ALGO; /* unsupport protection algorithm */
319         else {
320             cipher_hd = cipher_open( cert->protect.algo,
321                                      CIPHER_MODE_AUTO_CFB, 1 );
322             cipher_setkey( cipher_hd, dek->key, dek->keylen );
323             cipher_setiv( cipher_hd, NULL );
324             cipher_encrypt( cipher_hd, cert->protect.iv, cert->protect.iv, 8 );
325             if( !do_protect( &cipher_encrypt, cipher_hd, cert ) )
326                 cert->is_protected = 1;
327             cipher_close( cipher_hd );
328         }
329     }
330     return rc;
331 }
332