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