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