changed structure of trustdb
[gnupg.git] / g10 / seckey-cert.c
1 /* seckey-cert.c -  secret key certifucate packet handling
2  *      Copyright (c) 1997 by Werner Koch (dd9jn)
3  *
4  * This file is part of G10.
5  *
6  * G10 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  * G10 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             dek = get_passphrase_hash( keyid, NULL );
80             blowfish_ctx = m_alloc_secure( sizeof *blowfish_ctx );
81             blowfish_setkey( blowfish_ctx, dek->key, dek->keylen );
82             m_free(dek); /* pw is in secure memory, so m_free() burns it */
83             blowfish_setiv( blowfish_ctx, NULL );
84             memcpy(save_iv, cert->d.elg.protect.blowfish.iv, 8 );
85             blowfish_decode_cfb( blowfish_ctx,
86                                  cert->d.elg.protect.blowfish.iv,
87                                  cert->d.elg.protect.blowfish.iv, 8 );
88             mpi_set_secure(cert->d.elg.x );
89             /*fixme: maybe it is better to set the buger secure with a
90              * new get_buffer_secure() function */
91             buffer = mpi_get_buffer( cert->d.elg.x, &nbytes, NULL );
92             csum = checksum_u16( nbytes*8 );
93             blowfish_decode_cfb( blowfish_ctx, buffer, buffer, nbytes );
94             csum += checksum( buffer, nbytes );
95             test_x = mpi_alloc_secure( mpi_get_nlimbs(cert->d.elg.x) );
96             mpi_set_buffer( test_x, buffer, nbytes, 0 );
97             m_free( buffer );
98             m_free( blowfish_ctx );
99             /* now let's see wether we have used the right passphrase */
100             if( csum != cert->d.elg.csum ) {
101                 mpi_free(test_x);
102                 memcpy( cert->d.elg.protect.blowfish.iv, save_iv, 8 );
103                 return G10ERR_BAD_PASS;
104             }
105
106             skey.p = cert->d.elg.p;
107             skey.g = cert->d.elg.g;
108             skey.y = cert->d.elg.y;
109             skey.x = test_x;
110             res = elg_check_secret_key( &skey );
111             memset( &skey, 0, sizeof skey );
112             if( !res ) {
113                 mpi_free(test_x);
114                 memcpy( cert->d.elg.protect.blowfish.iv, save_iv, 8 );
115                 return G10ERR_BAD_PASS;
116             }
117             mpi_set(cert->d.elg.x, test_x);
118             mpi_free(test_x);
119             cert->d.elg.is_protected = 0;
120             break;
121
122           default:
123             return G10ERR_CIPHER_ALGO; /* unsupport protection algorithm */
124         }
125     }
126     else { /* not protected */
127         buffer = mpi_get_buffer( cert->d.elg.x, &nbytes, NULL );
128         csum = checksum_u16( nbytes*8 );
129         csum += checksum( buffer, nbytes );
130         m_free( buffer );
131         if( csum != cert->d.elg.csum )
132             return G10ERR_CHECKSUM;
133     }
134
135     return 0;
136 }
137
138 static int
139 protect_elg( PKT_secret_cert *cert, DEK *dek )
140 {
141     byte *buffer;
142     unsigned nbytes;
143
144     if( !cert->d.elg.is_protected ) { /* add the protection */
145         BLOWFISH_context *blowfish_ctx=NULL;
146
147         switch( cert->d.elg.protect_algo ) {
148           case CIPHER_ALGO_NONE: BUG(); break;
149           case CIPHER_ALGO_BLOWFISH:
150             blowfish_ctx = m_alloc_secure( sizeof *blowfish_ctx );
151             blowfish_setkey( blowfish_ctx, dek->key, dek->keylen );
152             blowfish_setiv( blowfish_ctx, NULL );
153             blowfish_encode_cfb( blowfish_ctx,
154                                  cert->d.elg.protect.blowfish.iv,
155                                  cert->d.elg.protect.blowfish.iv, 8 );
156             buffer = mpi_get_buffer( cert->d.elg.x, &nbytes, NULL );
157             blowfish_encode_cfb( blowfish_ctx, buffer, buffer, nbytes );
158             mpi_set_buffer( cert->d.elg.x, buffer, nbytes, 0 );
159             m_free( buffer );
160             m_free( blowfish_ctx );
161             cert->d.elg.is_protected = 1;
162             break;
163
164           default:
165             return G10ERR_CIPHER_ALGO; /* unsupport protection algorithm */
166         }
167     }
168     return 0;
169 }
170
171
172 #ifdef HAVE_RSA_CIPHER
173 static int
174 check_rsa( PKT_secret_cert *cert )
175 {
176     byte *buffer;
177     u16 csum=0;
178     int res;
179     unsigned nbytes;
180     u32 keyid[2];
181     RSA_secret_key skey;
182
183     if( cert->d.rsa.is_protected ) { /* remove the protection */
184         DEK *dek = NULL;
185         BLOWFISH_context *blowfish_ctx=NULL;
186
187         switch( cert->d.rsa.protect_algo ) {
188             /* FIXME: use test variables to check for the correct key */
189           case CIPHER_ALGO_NONE: BUG(); break;
190           case CIPHER_ALGO_BLOWFISH:
191             keyid_from_skc( cert, keyid );
192             dek = get_passphrase_hash( keyid, NULL );
193             blowfish_ctx = m_alloc_secure( sizeof *blowfish_ctx );
194             blowfish_setkey( blowfish_ctx, dek->key, dek->keylen );
195             m_free(dek); /* pw is in secure memory, so m_free() burns it */
196             blowfish_setiv( blowfish_ctx, NULL );
197             blowfish_decode_cfb( blowfish_ctx,
198                                  cert->d.rsa.protect.blowfish.iv,
199                                  cert->d.rsa.protect.blowfish.iv, 8 );
200             csum = 0;
201             #define X(a) do { \
202                 mpi_set_secure(cert->d.rsa.rsa_##a); \
203                 buffer = mpi_get_buffer( cert->d.rsa.rsa_##a, &nbytes, NULL );\
204                 csum += checksum_u16( nbytes*8 );                            \
205                 blowfish_decode_cfb( blowfish_ctx, buffer, buffer, nbytes ); \
206                 csum += checksum( buffer, nbytes );                          \
207                 mpi_set_buffer(cert->d.rsa.rsa_##a, buffer, nbytes, 0 );     \
208                 m_free( buffer );                                            \
209                } while(0)
210             X(d);
211             X(p);
212             X(q);
213             X(u);
214             #undef X
215             cert->d.rsa.is_protected = 0;
216             m_free( blowfish_ctx );
217             /* now let's see wether we have used the right passphrase */
218             if( csum != cert->d.rsa.csum )
219                 return G10ERR_BAD_PASS;
220
221             skey.d = cert->d.rsa.rsa_d;
222             skey.p = cert->d.rsa.rsa_p;
223             skey.q = cert->d.rsa.rsa_q;
224             skey.u = cert->d.rsa.rsa_u;
225             res = rsa_check_secret_key( &skey );
226             memset( &skey, 0, sizeof skey );
227             if( !res )
228                 return G10ERR_BAD_PASS;
229             break;
230
231           default:
232             return G10ERR_CIPHER_ALGO; /* unsupported protection algorithm */
233         }
234     }
235     else { /* not protected */
236         csum =0;
237         buffer = mpi_get_buffer( cert->d.rsa.rsa_d, &nbytes, NULL );
238         csum += checksum_u16( nbytes*8 );
239         csum += checksum( buffer, nbytes );
240         m_free( buffer );
241         buffer = mpi_get_buffer( cert->d.rsa.rsa_p, &nbytes, NULL );
242         csum += checksum_u16( nbytes*8 );
243         csum += checksum( buffer, nbytes );
244         m_free( buffer );
245         buffer = mpi_get_buffer( cert->d.rsa.rsa_q, &nbytes, NULL );
246         csum += checksum_u16( nbytes*8 );
247         csum += checksum( buffer, nbytes );
248         m_free( buffer );
249         buffer = mpi_get_buffer( cert->d.rsa.rsa_u, &nbytes, NULL );
250         csum += checksum_u16( nbytes*8 );
251         csum += checksum( buffer, nbytes );
252         m_free( buffer );
253         if( csum != cert->d.rsa.csum )
254             return G10ERR_CHECKSUM;
255     }
256
257     return 0;
258 }
259 #endif /*HAVE_RSA_CIPHER*/
260
261
262
263
264 /****************
265  * Check the secret key certificate
266  * Ask up to 3 time for a correct passphrase
267  */
268 int
269 check_secret_key( PKT_secret_cert *cert )
270 {
271     int rc = G10ERR_BAD_PASS;
272     int i;
273
274     for(i=0; i < 3 && rc == G10ERR_BAD_PASS; i++ ) {
275         if( i )
276             log_error("Invalid passphrase; please try again ...\n");
277         if( cert->pubkey_algo == PUBKEY_ALGO_ELGAMAL )
278             rc = check_elg( cert );
279       #ifdef HAVE_RSA_CIPHER
280         else if( cert->pubkey_algo == PUBKEY_ALGO_RSA )
281             rc = check_rsa( cert );
282       #endif
283         else
284             rc = G10ERR_PUBKEY_ALGO;
285         if( get_passphrase_fd() != -1 )
286             break;
287     }
288     return rc;
289 }
290
291 /****************
292  * check wether the secret key is protected.
293  * Returns: 0 not protected, -1 on error or the protection algorithm
294  */
295 int
296 is_secret_key_protected( PKT_secret_cert *cert )
297 {
298     if( cert->pubkey_algo == PUBKEY_ALGO_ELGAMAL )
299         return cert->d.elg.is_protected? cert->d.elg.protect_algo : 0;
300   #ifdef HAVE_RSA_CIPHER
301     else if( cert->pubkey_algo == PUBKEY_ALGO_RSA )
302         return cert->d.rsa.is_protected? cert->d.rsa.protect_algo : 0;
303   #endif
304     else
305         return -1; /* unsupported */
306 }
307
308
309 /****************
310  * Protect the secret key certificate with the passphrase from DEK
311  */
312 int
313 protect_secret_key( PKT_secret_cert *cert, DEK *dek )
314 {
315     if( !dek )
316         return 0;
317
318     if( cert->pubkey_algo == PUBKEY_ALGO_ELGAMAL )
319         return protect_elg( cert, dek );
320   #ifdef 0 /* noy yet implemented */
321     else if( cert->pubkey_algo == PUBKEY_ALGO_RSA )
322         return protect_rsa( cert, dek );
323   #endif
324     else
325         return G10ERR_PUBKEY_ALGO;
326 }
327