gnupg extension are now working
[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 #include "main.h"
33 #include "options.h"
34 #include "i18n.h"
35
36
37 static int
38 do_check( PKT_secret_cert *cert )
39 {
40     byte *buffer;
41     u16 csum=0;
42     int res;
43     unsigned nbytes;
44
45     if( cert->is_protected ) { /* remove the protection */
46         DEK *dek = NULL;
47         u32 keyid[2];
48         CIPHER_HANDLE cipher_hd=NULL;
49         PKT_secret_cert *save_cert;
50         char save_iv[8];
51
52         if( cert->protect.algo == CIPHER_ALGO_NONE )
53             BUG();
54         if( check_cipher_algo( cert->protect.algo ) )
55             return G10ERR_CIPHER_ALGO; /* unsupported protection algorithm */
56         keyid_from_skc( cert, keyid );
57         dek = passphrase_to_dek( keyid, cert->protect.algo,
58                                  &cert->protect.s2k, 0 );
59         cipher_hd = cipher_open( cert->protect.algo,
60                                  CIPHER_MODE_AUTO_CFB, 1);
61         cipher_setkey( cipher_hd, dek->key, dek->keylen );
62         cipher_setiv( cipher_hd, NULL );
63         m_free(dek); /* pw is in secure memory, so m_free() burns it */
64         save_cert = copy_secret_cert( NULL, cert );
65         memcpy(save_iv, cert->protect.iv, 8 );
66         cipher_decrypt( cipher_hd, cert->protect.iv, cert->protect.iv, 8 );
67         switch( cert->pubkey_algo ) {
68           case PUBKEY_ALGO_ELGAMAL:
69           case PUBKEY_ALGO_ELGAMAL_E:
70             /* FIXME: removed ELG knowledge from this function */
71             buffer = mpi_get_secure_buffer( cert->skey[3], &nbytes, NULL );
72             cipher_decrypt( cipher_hd, buffer, buffer, nbytes );
73             mpi_set_buffer( cert->skey[3], buffer, nbytes, 0 );
74             csum = checksum_mpi( cert->skey[3] );
75             m_free( buffer );
76             break;
77           case PUBKEY_ALGO_DSA:
78             buffer = mpi_get_secure_buffer( cert->skey[4], &nbytes, NULL );
79             cipher_decrypt( cipher_hd, buffer, buffer, nbytes );
80             mpi_set_buffer( cert->skey[4], buffer, nbytes, 0 );
81             csum = checksum_mpi( cert->skey[4] );
82             m_free( buffer );
83             break;
84           case PUBKEY_ALGO_RSA:
85           case PUBKEY_ALGO_RSA_E:
86           case PUBKEY_ALGO_RSA_S:
87             csum = 0;
88             #define X(a) do { \
89                 buffer = mpi_get_secure_buffer( cert->skey[(a)],     \
90                                                 &nbytes, NULL );     \
91                 csum += checksum_u16( nbytes*8 );                    \
92                 cipher_decrypt( cipher_hd, buffer, buffer, nbytes ); \
93                 csum += checksum( buffer, nbytes );                  \
94                 mpi_set_buffer(cert->skey[(a)], buffer, nbytes, 0 ); \
95                 m_free( buffer );                                    \
96                } while(0)
97             X(2);
98             X(3);
99             X(4);
100             X(5);
101             #undef X
102             break;
103
104           default: BUG();
105         }
106         cipher_close( cipher_hd );
107         /* now let's see whether we have used the right passphrase */
108         if( csum != cert->csum ) {
109             if( csum != cert->csum ) {
110                 copy_secret_cert( cert, save_cert );
111                 free_secret_cert( save_cert );
112                 memcpy( cert->protect.iv, save_iv, 8 );
113                 return G10ERR_BAD_PASS;
114             }
115         }
116
117         res = pubkey_check_secret_key( cert->pubkey_algo, cert->skey );
118         if( res ) {
119             copy_secret_cert( cert, save_cert );
120             free_secret_cert( save_cert );
121             memcpy( cert->protect.iv, save_iv, 8 );
122             return G10ERR_BAD_PASS;
123         }
124         free_secret_cert( save_cert );
125         cert->is_protected = 0;
126     }
127     else { /* not protected */
128         switch( cert->pubkey_algo ) {
129           case PUBKEY_ALGO_ELGAMAL_E:
130           case PUBKEY_ALGO_ELGAMAL:
131             csum = checksum_mpi( cert->skey[3] );
132             break;
133           case PUBKEY_ALGO_DSA:
134             csum = checksum_mpi( cert->skey[4] );
135             break;
136           case PUBKEY_ALGO_RSA_E:
137           case PUBKEY_ALGO_RSA_S:
138           case PUBKEY_ALGO_RSA:
139             csum =0;
140             buffer = mpi_get_buffer( cert->skey[2], &nbytes, NULL );
141             csum += checksum_u16( nbytes*8 );
142             csum += checksum( buffer, nbytes );
143             m_free( buffer );
144             buffer = mpi_get_buffer( cert->skey[3], &nbytes, NULL );
145             csum += checksum_u16( nbytes*8 );
146             csum += checksum( buffer, nbytes );
147             m_free( buffer );
148             buffer = mpi_get_buffer( cert->skey[4], &nbytes, NULL );
149             csum += checksum_u16( nbytes*8 );
150             csum += checksum( buffer, nbytes );
151             m_free( buffer );
152             buffer = mpi_get_buffer( cert->skey[5], &nbytes, NULL );
153             csum += checksum_u16( nbytes*8 );
154             csum += checksum( buffer, nbytes );
155             m_free( buffer );
156             break;
157           default: BUG();
158         }
159         if( csum != cert->csum )
160             return G10ERR_CHECKSUM;
161     }
162
163     return 0;
164 }
165
166
167
168 /****************
169  * Check the secret key certificate
170  * Ask up to 3 times for a correct passphrase
171  */
172 int
173 check_secret_key( PKT_secret_cert *cert )
174 {
175     int rc = G10ERR_BAD_PASS;
176     int i;
177
178     for(i=0; i < 3 && rc == G10ERR_BAD_PASS; i++ ) {
179         if( i )
180             log_error(_("Invalid passphrase; please try again ...\n"));
181         rc = do_check( cert );
182       #if 0 /* set to 1 to enable the workaround */
183         if( rc == G10ERR_BAD_PASS && cert->is_protected
184             && cert->protect.algo == CIPHER_ALGO_BLOWFISH
185             && cert->pubkey_algo != PUBKEY_ALGO_ELGAMAL ) {
186             /* Workaround for a bug in 0.2.16 which still used
187              * a 160 bit key for BLOWFISH. */
188             log_info("trying workaround for 0.2.16 passphrase bug ...\n");
189             log_info("If you don't need this, uncomment it in g10/seckey-cert.c\n\n");
190             cert->protect.algo = CIPHER_ALGO_BLOWFISH160;
191             rc = do_check( cert );
192             if( rc )
193                 rc = G10ERR_BAD_PASS;
194             cert->protect.algo = CIPHER_ALGO_BLOWFISH;
195         }
196       #endif
197         if( get_passphrase_fd() != -1 )
198             break;
199     }
200
201     return rc;
202 }
203
204 /****************
205  * check whether the secret key is protected.
206  * Returns: 0 not protected, -1 on error or the protection algorithm
207  */
208 int
209 is_secret_key_protected( PKT_secret_cert *cert )
210 {
211     return cert->is_protected? cert->protect.algo : 0;
212 }
213
214
215 static int
216 do_protect( void (*fnc)(CIPHER_HANDLE, byte *, byte *, unsigned),
217             CIPHER_HANDLE fnc_hd, PKT_secret_cert *cert )
218 {
219     byte *buffer;
220     unsigned nbytes;
221
222     switch( cert->pubkey_algo ) {
223       case PUBKEY_ALGO_ELGAMAL_E:
224       case PUBKEY_ALGO_ELGAMAL:
225         buffer = mpi_get_buffer( cert->skey[3], &nbytes, NULL );
226         (*fnc)( fnc_hd, buffer, buffer, nbytes );
227         mpi_set_buffer( cert->skey[3], buffer, nbytes, 0 );
228         m_free( buffer );
229         break;
230
231       case PUBKEY_ALGO_DSA:
232         buffer = mpi_get_buffer( cert->skey[4], &nbytes, NULL );
233         (*fnc)( fnc_hd, buffer, buffer, nbytes );
234         mpi_set_buffer( cert->skey[4], buffer, nbytes, 0 );
235         m_free( buffer );
236         break;
237
238       default: return G10ERR_PUBKEY_ALGO;
239     }
240     return 0;
241 }
242
243
244 /****************
245  * Protect the secret key certificate with the passphrase from DEK
246  */
247 int
248 protect_secret_key( PKT_secret_cert *cert, DEK *dek )
249 {
250     int rc=0;
251
252     if( !dek )
253         return 0;
254
255     if( !cert->is_protected ) { /* okay, apply the protection */
256         CIPHER_HANDLE cipher_hd=NULL;
257
258         if( check_cipher_algo( cert->protect.algo ) )
259             rc = G10ERR_CIPHER_ALGO; /* unsupport protection algorithm */
260         else {
261             cipher_hd = cipher_open( cert->protect.algo,
262                                      CIPHER_MODE_AUTO_CFB, 1 );
263             cipher_setkey( cipher_hd, dek->key, dek->keylen );
264             cipher_setiv( cipher_hd, NULL );
265             cipher_encrypt( cipher_hd, cert->protect.iv, cert->protect.iv, 8 );
266             if( !do_protect( &cipher_encrypt, cipher_hd, cert ) )
267                 cert->is_protected = 1;
268             cipher_close( cipher_hd );
269         }
270     }
271     return rc;
272 }
273