extensions are now working and fixed a lot of bugs
[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 i, 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);
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         csum = 0;
68         for(i=pubkey_get_npkey(cert->pubkey_algo);
69                 i < pubkey_get_nskey(cert->pubkey_algo); i++ ) {
70             buffer = mpi_get_secure_buffer( cert->skey[i], &nbytes, NULL );
71             cipher_sync( cipher_hd );
72             cipher_decrypt( cipher_hd, buffer, buffer, nbytes );
73             mpi_set_buffer( cert->skey[i], buffer, nbytes, 0 );
74             csum += checksum_mpi( cert->skey[i] );
75             m_free( buffer );
76         }
77         if( opt.emulate_bugs & 1 ) {
78            log_debug("secret key csum is=%04hx should=%04hx algos=%d/%d\n",
79                      csum, cert->csum, cert->pubkey_algo,cert->protect.algo );
80            csum = cert->csum;
81         }
82         cipher_close( cipher_hd );
83         /* now let's see whether we have used the right passphrase */
84         if( csum != cert->csum ) {
85             copy_secret_cert( cert, save_cert );
86             free_secret_cert( save_cert );
87             memcpy( cert->protect.iv, save_iv, 8 );
88             return G10ERR_BAD_PASS;
89         }
90         /* the checksum may fail, so we also check the key itself */
91         res = pubkey_check_secret_key( cert->pubkey_algo, cert->skey );
92         if( res ) {
93             copy_secret_cert( cert, save_cert );
94             free_secret_cert( save_cert );
95             memcpy( cert->protect.iv, save_iv, 8 );
96             return G10ERR_BAD_PASS;
97         }
98         free_secret_cert( save_cert );
99         cert->is_protected = 0;
100     }
101     else { /* not protected, assume it is okay if the checksum is okay */
102         csum = 0;
103         for(i=pubkey_get_npkey(cert->pubkey_algo);
104                 i < pubkey_get_nskey(cert->pubkey_algo); i++ ) {
105             csum += checksum_mpi( cert->skey[i] );
106         }
107         if( csum != cert->csum )
108             return G10ERR_CHECKSUM;
109     }
110
111     return 0;
112 }
113
114
115
116 /****************
117  * Check the secret key certificate
118  * Ask up to 3 times for a correct passphrase
119  */
120 int
121 check_secret_key( PKT_secret_cert *cert )
122 {
123     int rc = G10ERR_BAD_PASS;
124     int i;
125
126     for(i=0; i < 3 && rc == G10ERR_BAD_PASS; i++ ) {
127         if( i )
128             log_error(_("Invalid passphrase; please try again ...\n"));
129         rc = do_check( cert );
130       #if 0 /* set to 1 to enable the workaround */
131         if( rc == G10ERR_BAD_PASS && cert->is_protected
132             && cert->protect.algo == CIPHER_ALGO_BLOWFISH
133             && cert->pubkey_algo != PUBKEY_ALGO_ELGAMAL ) {
134             /* Workaround for a bug in 0.2.16 which still used
135              * a 160 bit key for BLOWFISH. */
136             log_info("trying workaround for 0.2.16 passphrase bug ...\n");
137             log_info("If you don't need this, uncomment it in g10/seckey-cert.c\n\n");
138             cert->protect.algo = CIPHER_ALGO_BLOWFISH160;
139             rc = do_check( cert );
140             if( rc )
141                 rc = G10ERR_BAD_PASS;
142             cert->protect.algo = CIPHER_ALGO_BLOWFISH;
143         }
144       #endif
145         if( get_passphrase_fd() != -1 )
146             break;
147     }
148
149     return rc;
150 }
151
152 /****************
153  * check whether the secret key is protected.
154  * Returns: 0 not protected, -1 on error or the protection algorithm
155  */
156 int
157 is_secret_key_protected( PKT_secret_cert *cert )
158 {
159     return cert->is_protected? cert->protect.algo : 0;
160 }
161
162
163
164 /****************
165  * Protect the secret key certificate with the passphrase from DEK
166  */
167 int
168 protect_secret_key( PKT_secret_cert *cert, DEK *dek )
169 {
170     int i, rc = 0;
171     byte *buffer;
172     unsigned nbytes;
173     u16 csum;
174
175     if( !dek )
176         return 0;
177
178     if( !cert->is_protected ) { /* okay, apply the protection */
179         CIPHER_HANDLE cipher_hd=NULL;
180
181         if( check_cipher_algo( cert->protect.algo ) )
182             rc = G10ERR_CIPHER_ALGO; /* unsupport protection algorithm */
183         else {
184             cipher_hd = cipher_open( cert->protect.algo,
185                                      CIPHER_MODE_AUTO_CFB, 1 );
186             cipher_setkey( cipher_hd, dek->key, dek->keylen );
187             cipher_setiv( cipher_hd, NULL );
188             cipher_encrypt( cipher_hd, cert->protect.iv, cert->protect.iv, 8 );
189             /* NOTE: we always recalculate the checksum because there are some
190              * test releases which calculated it wrong */
191             csum = 0;
192             for(i=pubkey_get_npkey(cert->pubkey_algo);
193                     i < pubkey_get_nskey(cert->pubkey_algo); i++ ) {
194                 csum += checksum_mpi_counted_nbits( cert->skey[i] );
195                 buffer = mpi_get_buffer( cert->skey[i], &nbytes, NULL );
196            log_debug("protecing i=%d csum=%04hx nbytes=%u\n", i, csum, nbytes );
197                 cipher_sync( cipher_hd );
198                 cipher_encrypt( cipher_hd, buffer, buffer, nbytes );
199                 mpi_set_buffer( cert->skey[i], buffer, nbytes, 0 );
200                 m_free( buffer );
201             }
202             cert->csum = csum;
203             cert->is_protected = 1;
204             cipher_close( cipher_hd );
205         }
206     }
207     return rc;
208 }
209