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