Renamed to GNUPG
[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 static int
145 protect_elg( PKT_secret_cert *cert, DEK *dek )
146 {
147     byte *buffer;
148     unsigned nbytes;
149
150     if( !cert->d.elg.is_protected ) { /* add the protection */
151         BLOWFISH_context *blowfish_ctx=NULL;
152
153         switch( cert->d.elg.protect.algo ) {
154           case CIPHER_ALGO_NONE: BUG(); break;
155           case CIPHER_ALGO_BLOWFISH:
156             blowfish_ctx = m_alloc_secure( sizeof *blowfish_ctx );
157             blowfish_setkey( blowfish_ctx, dek->key, dek->keylen );
158             blowfish_setiv( blowfish_ctx, NULL );
159             blowfish_encode_cfb( blowfish_ctx,
160                                  cert->d.elg.protect.iv,
161                                  cert->d.elg.protect.iv, 8 );
162             buffer = mpi_get_buffer( cert->d.elg.x, &nbytes, NULL );
163             blowfish_encode_cfb( blowfish_ctx, buffer, buffer, nbytes );
164             mpi_set_buffer( cert->d.elg.x, buffer, nbytes, 0 );
165             m_free( buffer );
166             m_free( blowfish_ctx );
167             cert->d.elg.is_protected = 1;
168             break;
169
170           default:
171             return G10ERR_CIPHER_ALGO; /* unsupport protection algorithm */
172         }
173     }
174     return 0;
175 }
176
177
178 #ifdef HAVE_RSA_CIPHER
179 static int
180 check_rsa( PKT_secret_cert *cert )
181 {
182     byte *buffer;
183     u16 csum=0;
184     int res;
185     unsigned nbytes;
186     u32 keyid[2];
187     RSA_secret_key skey;
188
189     if( cert->d.rsa.is_protected ) { /* remove the protection */
190         DEK *dek = NULL;
191         BLOWFISH_context *blowfish_ctx=NULL;
192
193         switch( cert->d.rsa.protect_algo ) {
194             /* FIXME: use test variables to check for the correct key */
195           case CIPHER_ALGO_NONE: BUG(); break;
196           case CIPHER_ALGO_BLOWFISH:
197             keyid_from_skc( cert, keyid );
198             dek = get_passphrase_hash( keyid, NULL );
199             blowfish_ctx = m_alloc_secure( sizeof *blowfish_ctx );
200             blowfish_setkey( blowfish_ctx, dek->key, dek->keylen );
201             m_free(dek); /* pw is in secure memory, so m_free() burns it */
202             blowfish_setiv( blowfish_ctx, NULL );
203             blowfish_decode_cfb( blowfish_ctx,
204                                  cert->d.rsa.protect.blowfish.iv,
205                                  cert->d.rsa.protect.blowfish.iv, 8 );
206             csum = 0;
207             #define X(a) do { \
208                 mpi_set_secure(cert->d.rsa.rsa_##a); \
209                 buffer = mpi_get_buffer( cert->d.rsa.rsa_##a, &nbytes, NULL );\
210                 csum += checksum_u16( nbytes*8 );                            \
211                 blowfish_decode_cfb( blowfish_ctx, buffer, buffer, nbytes ); \
212                 csum += checksum( buffer, nbytes );                          \
213                 mpi_set_buffer(cert->d.rsa.rsa_##a, buffer, nbytes, 0 );     \
214                 m_free( buffer );                                            \
215                } while(0)
216             X(d);
217             X(p);
218             X(q);
219             X(u);
220             #undef X
221             cert->d.rsa.is_protected = 0;
222             m_free( blowfish_ctx );
223             /* now let's see wether we have used the right passphrase */
224             if( csum != cert->d.rsa.csum )
225                 return G10ERR_BAD_PASS;
226
227             skey.d = cert->d.rsa.rsa_d;
228             skey.p = cert->d.rsa.rsa_p;
229             skey.q = cert->d.rsa.rsa_q;
230             skey.u = cert->d.rsa.rsa_u;
231             res = rsa_check_secret_key( &skey );
232             memset( &skey, 0, sizeof skey );
233             if( !res )
234                 return G10ERR_BAD_PASS;
235             break;
236
237           default:
238             return G10ERR_CIPHER_ALGO; /* unsupported protection algorithm */
239         }
240     }
241     else { /* not protected */
242         csum =0;
243         buffer = mpi_get_buffer( cert->d.rsa.rsa_d, &nbytes, NULL );
244         csum += checksum_u16( nbytes*8 );
245         csum += checksum( buffer, nbytes );
246         m_free( buffer );
247         buffer = mpi_get_buffer( cert->d.rsa.rsa_p, &nbytes, NULL );
248         csum += checksum_u16( nbytes*8 );
249         csum += checksum( buffer, nbytes );
250         m_free( buffer );
251         buffer = mpi_get_buffer( cert->d.rsa.rsa_q, &nbytes, NULL );
252         csum += checksum_u16( nbytes*8 );
253         csum += checksum( buffer, nbytes );
254         m_free( buffer );
255         buffer = mpi_get_buffer( cert->d.rsa.rsa_u, &nbytes, NULL );
256         csum += checksum_u16( nbytes*8 );
257         csum += checksum( buffer, nbytes );
258         m_free( buffer );
259         if( csum != cert->d.rsa.csum )
260             return G10ERR_CHECKSUM;
261     }
262
263     return 0;
264 }
265 #endif /*HAVE_RSA_CIPHER*/
266
267
268
269
270 /****************
271  * Check the secret key certificate
272  * Ask up to 3 time for a correct passphrase
273  */
274 int
275 check_secret_key( PKT_secret_cert *cert )
276 {
277     int rc = G10ERR_BAD_PASS;
278     int i;
279
280     for(i=0; i < 3 && rc == G10ERR_BAD_PASS; i++ ) {
281         if( i )
282             log_error("Invalid passphrase; please try again ...\n");
283         if( cert->pubkey_algo == PUBKEY_ALGO_ELGAMAL )
284             rc = check_elg( cert );
285       #ifdef HAVE_RSA_CIPHER
286         else if( cert->pubkey_algo == PUBKEY_ALGO_RSA )
287             rc = check_rsa( cert );
288       #endif
289         else
290             rc = G10ERR_PUBKEY_ALGO;
291         if( get_passphrase_fd() != -1 )
292             break;
293     }
294     return rc;
295 }
296
297 /****************
298  * check wether the secret key is protected.
299  * Returns: 0 not protected, -1 on error or the protection algorithm
300  */
301 int
302 is_secret_key_protected( PKT_secret_cert *cert )
303 {
304     if( cert->pubkey_algo == PUBKEY_ALGO_ELGAMAL )
305         return cert->d.elg.is_protected? cert->d.elg.protect.algo : 0;
306   #ifdef HAVE_RSA_CIPHER
307     else if( cert->pubkey_algo == PUBKEY_ALGO_RSA )
308         return cert->d.rsa.is_protected? cert->d.rsa.protect_algo : 0;
309   #endif
310     else
311         return -1; /* unsupported */
312 }
313
314
315 /****************
316  * Protect the secret key certificate with the passphrase from DEK
317  */
318 int
319 protect_secret_key( PKT_secret_cert *cert, DEK *dek )
320 {
321     if( !dek )
322         return 0;
323
324     if( cert->pubkey_algo == PUBKEY_ALGO_ELGAMAL )
325         return protect_elg( cert, dek );
326     else
327         return G10ERR_PUBKEY_ALGO;
328 }
329