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