initially checkin
[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
34 static u16
35 checksum( byte *p )
36 {
37     u16 n, a;
38
39     n = *p++ << 8;
40     n |= *p++;
41     for(a=0; n; n-- )
42         a += *p++;
43     return a;
44 }
45
46
47 /****************
48  * Check the secret key certificate
49  */
50 int
51 check_secret_key( PKT_seckey_cert *cert )
52 {
53     IDEA_context idea_ctx;  /* FIXME: allocate this in secure space ! */
54     byte iv[8];
55     byte *mpibuf;
56     u16 n;
57     MPI temp_mpi;
58     int res;
59     u32 keyid[2];
60
61 #if IDEA_BLOCKSIZE != 8 || BLOWFISH_BLOCKSIZE != 8
62   #error unsupportted blocksize
63 #endif
64
65     if( cert->pubkey_algo != PUBKEY_ALGO_RSA )
66         return G10ERR_PUBKEY_ALGO; /* unsupport algorithm */
67
68     if( cert->d.rsa.is_protected ) { /* remove the protection */
69         DEK *dek = NULL;
70         BLOWFISH_context *blowfish_ctx=NULL;
71
72         switch( cert->d.rsa.protect_algo ) {
73           case CIPHER_ALGO_NONE:
74             log_bug("unprotect seckey_cert is flagged protected\n");
75             break;
76           case CIPHER_ALGO_IDEA:
77           case CIPHER_ALGO_BLOWFISH:
78             mpi_get_keyid( cert->d.rsa.rsa_n , keyid );
79             dek = get_passphrase_hash( keyid, NULL );
80
81           /*  idea_setkey( &idea_ctx, dpw );*/
82             m_free(dek); /* pw is in secure memory, so m_free() burns it */
83             memset( iv, 0, BLOWFISH_BLOCKSIZE );
84             if( cert->d.rsa.protect_algo == CIPHER_ALGO_IDEA ) {
85                 idea_setiv( &idea_ctx, iv );
86                 /* fixme: is it save to leave the IV unencrypted in the
87                  * certificate or should we move it to secure storage? */
88                 idea_decode_cfb( &idea_ctx, cert->d.rsa.protect.idea.iv,
89                                             cert->d.rsa.protect.idea.iv, 8 );
90             }
91             else {
92                 blowfish_ctx = m_alloc_secure( sizeof *blowfish_ctx );
93                 blowfish_setiv( blowfish_ctx, iv );
94                 blowfish_decode_cfb( blowfish_ctx,
95                                      cert->d.rsa.protect.blowfish.iv,
96                                      cert->d.rsa.protect.blowfish.iv, 8 );
97             }
98             cert->d.rsa.calc_csum = 0;
99           #define X(a) do {                                             \
100                     mpibuf = (byte*)cert->d.rsa.rsa_##a;                \
101                     n = ((mpibuf[0] << 8) | mpibuf[1])-2;               \
102                     if( blowfish_ctx )                                  \
103                         blowfish_decode_cfb( blowfish_ctx,              \
104                                              mpibuf+4, mpibuf+4, n );   \
105                     else                                                 \
106                         idea_decode_cfb( &idea_ctx, mpibuf+4, mpibuf+4, n );\
107                     cert->d.rsa.calc_csum += checksum( mpibuf );        \
108                     cert->d.rsa.rsa_##a = mpi_decode_buffer( mpibuf );  \
109                     m_free( mpibuf );                                   \
110                 } while(0)
111             X(d);
112             X(p);
113             X(q);
114             X(u);
115           #undef X
116             m_free( blowfish_ctx );
117             cert->d.rsa.is_protected = 0;
118           #if 0
119             #define X(a) do { printf("\tRSA " #a ": ");                   \
120                               mpi_print(stdout, cert->d.rsa.rsa_##a, 1 ); \
121                               putchar('\n');                              \
122                             } while(0)
123             X(n);
124             X(e);
125             X(d);
126             X(p);
127             X(q);
128             X(u);
129             #undef X
130           #endif
131             /* now let's see wether we have used the right passphrase */
132             if( cert->d.rsa.calc_csum != cert->d.rsa.csum )
133                 return G10ERR_BAD_PASS;
134             temp_mpi = mpi_alloc(40);
135             mpi_mul(temp_mpi, cert->d.rsa.rsa_p, cert->d.rsa.rsa_q );
136             res = mpi_cmp( temp_mpi, cert->d.rsa.rsa_n );
137             mpi_free(temp_mpi);
138             if( res )
139                 return G10ERR_BAD_PASS;
140             break;
141
142           default:
143             return G10ERR_CIPHER_ALGO; /* unsupport protection algorithm */
144         }
145     }
146     /* must check the checksum here, because we didn't do it when
147      * parsing an unprotected certificate */
148     if( cert->d.rsa.calc_csum != cert->d.rsa.csum ) {
149         log_error("checksum in secret key certificate is wrong\n");
150         log_debug("stored csum=%04hx calculated csum=%04hx\n",
151                    cert->d.rsa.csum, cert->d.rsa.calc_csum );
152         return G10ERR_CHECKSUM;
153     }
154     return 0;
155 }
156
157