1 /* crypto.c: crytography-related functions
2 Copyright (c) 2002-2005 Philip Kendall
3
4 $Id: crypto.c 3698 2008-06-30 15:12:02Z pak21 $
5
6 This program 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 This program 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 along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20 Author contact information:
21
22 E-mail: philip-fuse@shadowmagic.org.uk
23
24 */
25
26 #include <config.h>
27
28 #ifdef HAVE_GCRYPT_H
29
30 #include <gcrypt.h>
31
32 #include "internals.h"
33
34 static const char *private_key_format =
35 "(key-data (private-key (dsa (p %m) (q %m) (g %m) (y %m) (x %m))))";
36 static const char *public_key_format =
37 "(key-data (public-key (dsa (p %m) (q %m) (g %m) (y %m))))";
38 static const char *hash_format = "(data (flags raw) (value %m))";
39 static const char *signature_format = "(sig-val (dsa (r %m) (s %m)))";
40
41 #define HASH_ALGORITHM GCRY_MD_SHA1
42 #define MPI_COUNT 5
43
44 static libspectrum_error
45 get_signature( gcry_mpi_t *r, gcry_mpi_t *s, libspectrum_byte *data,
46 size_t data_length, libspectrum_rzx_dsa_key *key );
47 static libspectrum_error
48 get_hash( gcry_sexp_t *hash, const libspectrum_byte *data,
49 size_t data_length );
50 static libspectrum_error
51 create_key( gcry_sexp_t *s_key, libspectrum_rzx_dsa_key *key, int secret_key);
52 static void free_mpis( gcry_mpi_t *mpis, size_t n );
53 static libspectrum_error get_mpi( gcry_mpi_t *mpi, gcry_sexp_t signature,
54 const char *token );
55 static libspectrum_error
56 serialise_mpis( libspectrum_byte **signature, size_t *signature_length,
57 gcry_mpi_t r, gcry_mpi_t s );
58
59 libspectrum_error
libspectrum_sign_data(libspectrum_byte ** signature,size_t * signature_length,libspectrum_byte * data,size_t data_length,libspectrum_rzx_dsa_key * key)60 libspectrum_sign_data( libspectrum_byte **signature, size_t *signature_length,
61 libspectrum_byte *data, size_t data_length,
62 libspectrum_rzx_dsa_key *key )
63 {
64 int error;
65 gcry_mpi_t r, s;
66
67 error = get_signature( &r, &s, data, data_length, key );
68 if( error ) return error;
69
70 error = serialise_mpis( signature, signature_length, r, s );
71 if( error ) { gcry_mpi_release( r ); gcry_mpi_release( s ); return error; }
72
73 gcry_mpi_release( r ); gcry_mpi_release( s );
74
75 return LIBSPECTRUM_ERROR_NONE;
76 }
77
78 static libspectrum_error
get_signature(gcry_mpi_t * r,gcry_mpi_t * s,libspectrum_byte * data,size_t data_length,libspectrum_rzx_dsa_key * key)79 get_signature( gcry_mpi_t *r, gcry_mpi_t *s, libspectrum_byte *data,
80 size_t data_length, libspectrum_rzx_dsa_key *key )
81 {
82 libspectrum_error error;
83 gcry_error_t gcrypt_error;
84 gcry_sexp_t hash, s_key, s_signature;
85
86 error = get_hash( &hash, data, data_length ); if( error ) return error;
87
88 error = create_key( &s_key, key, 1 );
89 if( error ) { gcry_sexp_release( hash ); return error; }
90
91 gcrypt_error = gcry_pk_sign( &s_signature, hash, s_key );
92 if( gcrypt_error ) {
93 libspectrum_print_error( LIBSPECTRUM_ERROR_LOGIC,
94 "get_signature: error signing data: %s",
95 gcry_strerror( gcrypt_error ) );
96 gcry_sexp_release( s_key ); gcry_sexp_release( hash );
97 return LIBSPECTRUM_ERROR_LOGIC;
98 }
99
100 gcry_sexp_release( s_key ); gcry_sexp_release( hash );
101
102 error = get_mpi( r, s_signature, "r" );
103 if( error ) { gcry_sexp_release( s_signature ); return error; }
104 error = get_mpi( s, s_signature, "s" );
105 if( error ) {
106 gcry_sexp_release( s_signature ); gcry_mpi_release( *r );
107 return error;
108 }
109
110 gcry_sexp_release( s_signature );
111
112 return LIBSPECTRUM_ERROR_NONE;
113 }
114
115 static libspectrum_error
get_hash(gcry_sexp_t * hash,const libspectrum_byte * data,size_t data_length)116 get_hash( gcry_sexp_t *hash, const libspectrum_byte *data, size_t data_length )
117 {
118 gcry_error_t error;
119 unsigned char *digest; size_t digest_length;
120 gcry_mpi_t hash_mpi;
121
122 digest_length = gcry_md_get_algo_dlen( HASH_ALGORITHM );
123 digest = libspectrum_malloc( digest_length );
124
125 gcry_md_hash_buffer( HASH_ALGORITHM, digest, data, data_length );
126
127 error = gcry_mpi_scan( &hash_mpi, GCRYMPI_FMT_USG, digest, digest_length,
128 NULL );
129 if( error ) {
130 libspectrum_print_error( LIBSPECTRUM_ERROR_LOGIC,
131 "get_hash: error creating hash MPI: %s",
132 gcry_strerror( error )
133 );
134 libspectrum_free( digest );
135 return LIBSPECTRUM_ERROR_LOGIC;
136 }
137
138 libspectrum_free( digest );
139
140 error = gcry_sexp_build( hash, NULL, hash_format, hash_mpi );
141 if( error ) {
142 libspectrum_print_error( LIBSPECTRUM_ERROR_LOGIC,
143 "get_hash: error creating hash sexp: %s",
144 gcry_strerror( error )
145 );
146 gcry_mpi_release( hash_mpi );
147 return LIBSPECTRUM_ERROR_LOGIC;
148 }
149
150 gcry_mpi_release( hash_mpi );
151
152 return LIBSPECTRUM_ERROR_NONE;
153 }
154
155 static libspectrum_error
create_key(gcry_sexp_t * s_key,libspectrum_rzx_dsa_key * key,int secret_key)156 create_key( gcry_sexp_t *s_key, libspectrum_rzx_dsa_key *key,
157 int secret_key )
158 {
159 gcry_error_t error;
160 size_t i;
161 gcry_mpi_t mpis[MPI_COUNT];
162 const char *format;
163
164 for( i=0; i<MPI_COUNT; i++ ) mpis[i] = NULL;
165
166 error = gcry_mpi_scan( &mpis[0], GCRYMPI_FMT_HEX, (unsigned char*)key->p,
167 0, NULL );
168 if( !error )
169 error = gcry_mpi_scan( &mpis[1], GCRYMPI_FMT_HEX, (unsigned char*)key->q,
170 0, NULL );
171 if( !error )
172 error = gcry_mpi_scan( &mpis[2], GCRYMPI_FMT_HEX, (unsigned char*)key->g,
173 0, NULL );
174 if( !error )
175 error = gcry_mpi_scan( &mpis[3], GCRYMPI_FMT_HEX, (unsigned char*)key->y,
176 0, NULL );
177 if( !error && secret_key )
178 error = gcry_mpi_scan( &mpis[4], GCRYMPI_FMT_HEX, (unsigned char*)key->x,
179 0, NULL );
180
181 if( error ) {
182 libspectrum_print_error( LIBSPECTRUM_ERROR_LOGIC,
183 "create_key: error creating MPIs: %s",
184 gcry_strerror( error ) );
185 free_mpis( mpis, MPI_COUNT );
186 return LIBSPECTRUM_ERROR_LOGIC;
187 }
188
189 format = secret_key ? private_key_format : public_key_format;
190
191 error = gcry_sexp_build( s_key, NULL, format,
192 mpis[0], mpis[1], mpis[2], mpis[3], mpis[4] );
193 if( error ) {
194 libspectrum_print_error( LIBSPECTRUM_ERROR_LOGIC,
195 "create_key: error creating key: %s",
196 gcry_strerror( error ) );
197 free_mpis( mpis, MPI_COUNT );
198 return LIBSPECTRUM_ERROR_LOGIC;
199 }
200
201 free_mpis( mpis, MPI_COUNT );
202
203 /* FIXME: Test public keys as well once gcry_pk_testkey acquires this
204 functionality */
205 if( secret_key ) {
206 error = gcry_pk_testkey( *s_key );
207 if( error ) {
208 libspectrum_print_error( LIBSPECTRUM_ERROR_LOGIC,
209 "create_key: key is not sane: %s",
210 gcry_strerror( error ) );
211 return LIBSPECTRUM_ERROR_LOGIC;
212 }
213 }
214
215 return LIBSPECTRUM_ERROR_NONE;
216 }
217
218 static void
free_mpis(gcry_mpi_t * mpis,size_t n)219 free_mpis( gcry_mpi_t *mpis, size_t n )
220 {
221 size_t i;
222 for( i=0; i<n; i++ ) if( mpis[i] ) gcry_mpi_release( mpis[i] );
223 }
224
225 static libspectrum_error
get_mpi(gcry_mpi_t * mpi,gcry_sexp_t sexp,const char * token)226 get_mpi( gcry_mpi_t *mpi, gcry_sexp_t sexp, const char *token )
227 {
228 gcry_sexp_t pair;
229
230 pair = gcry_sexp_find_token( sexp, token, strlen( token ) );
231 if( !pair ) {
232 libspectrum_print_error( LIBSPECTRUM_ERROR_LOGIC,
233 "get_mpis: couldn't find '%s'", token );
234 return LIBSPECTRUM_ERROR_LOGIC;
235 }
236
237 *mpi = gcry_sexp_nth_mpi( pair, 1, GCRYMPI_FMT_STD );
238 if( !(*mpi) ) {
239 libspectrum_print_error( LIBSPECTRUM_ERROR_LOGIC,
240 "get_mpis: couldn't create MPI '%s'", token );
241 return LIBSPECTRUM_ERROR_LOGIC;
242 }
243
244 return LIBSPECTRUM_ERROR_NONE;
245 }
246
247 static libspectrum_error
serialise_mpis(libspectrum_byte ** signature,size_t * signature_length,gcry_mpi_t r,gcry_mpi_t s)248 serialise_mpis( libspectrum_byte **signature, size_t *signature_length,
249 gcry_mpi_t r, gcry_mpi_t s )
250 {
251 gcry_error_t error;
252 size_t length, length_s;
253 unsigned char *ptr;
254
255 error = gcry_mpi_print( GCRYMPI_FMT_PGP, NULL, 0, &length, r );
256 if( error ) {
257 libspectrum_print_error( LIBSPECTRUM_ERROR_LOGIC,
258 "serialise_mpis: length of r: %s",
259 gcry_strerror( error ) );
260 return LIBSPECTRUM_ERROR_LOGIC;
261 }
262
263 error = gcry_mpi_print( GCRYMPI_FMT_PGP, NULL, 0, &length_s, s );
264 if( error ) {
265 libspectrum_print_error( LIBSPECTRUM_ERROR_LOGIC,
266 "serialise_mpis: length of s: %s",
267 gcry_strerror( error ) );
268 return LIBSPECTRUM_ERROR_LOGIC;
269 }
270
271 length += length_s; *signature_length = length;
272
273 *signature = libspectrum_malloc( length );
274
275 error = gcry_mpi_print( GCRYMPI_FMT_PGP, *signature, length, &length, r );
276 if( error ) {
277 libspectrum_print_error( LIBSPECTRUM_ERROR_LOGIC,
278 "serialise_mpis: printing r: %s",
279 gcry_strerror( error ) );
280 libspectrum_free( *signature );
281 return LIBSPECTRUM_ERROR_LOGIC;
282 }
283
284 ptr = *signature + length; length = *signature_length - length;
285 error = gcry_mpi_print( GCRYMPI_FMT_PGP, ptr, length, NULL, s );
286 if( error ) {
287 libspectrum_print_error( LIBSPECTRUM_ERROR_LOGIC,
288 "serialise_mpis: printing s: %s",
289 gcry_strerror( error ) );
290 libspectrum_free( *signature );
291 return LIBSPECTRUM_ERROR_LOGIC;
292 }
293
294 return LIBSPECTRUM_ERROR_NONE;
295 }
296
297 #include <stdio.h>
298
299 libspectrum_error
libspectrum_verify_signature(libspectrum_signature * signature,libspectrum_rzx_dsa_key * key)300 libspectrum_verify_signature( libspectrum_signature *signature,
301 libspectrum_rzx_dsa_key *key )
302 {
303 libspectrum_error error;
304 gcry_error_t gcrypt_error;
305 gcry_sexp_t hash, key_sexp, signature_sexp;
306
307 error = get_hash( &hash, signature->start, signature->length );
308 if( error ) return error;
309
310 error = create_key( &key_sexp, key, 0 );
311 if( error ) { gcry_sexp_release( hash ); return error; }
312
313 error = gcry_sexp_build( &signature_sexp, NULL, signature_format,
314 signature->r, signature->s );
315
316 if( error ) {
317 libspectrum_print_error(
318 LIBSPECTRUM_ERROR_LOGIC,
319 "create_signature: error building signature sexp: %s",
320 gcry_strerror( error )
321 );
322 gcry_sexp_release( key_sexp ); gcry_sexp_release( hash );
323 return LIBSPECTRUM_ERROR_LOGIC;
324 }
325
326 gcrypt_error = gcry_pk_verify( signature_sexp, hash, key_sexp );
327
328 gcry_sexp_release( signature_sexp );
329 gcry_sexp_release( key_sexp ); gcry_sexp_release( hash );
330
331 if( gcrypt_error ) {
332 if( gcry_err_code( gcrypt_error ) == GPG_ERR_BAD_SIGNATURE ) {
333 return LIBSPECTRUM_ERROR_SIGNATURE;
334 } else {
335 libspectrum_print_error(
336 LIBSPECTRUM_ERROR_LOGIC,
337 "libgcrypt error verifying signature: %s",
338 gcry_strerror( gcrypt_error )
339 );
340 return LIBSPECTRUM_ERROR_LOGIC;
341 }
342 }
343
344 return LIBSPECTRUM_ERROR_NONE;
345 }
346
347 libspectrum_error
libspectrum_signature_free(libspectrum_signature * signature)348 libspectrum_signature_free( libspectrum_signature *signature )
349 {
350 gcry_mpi_release( signature->r ); gcry_mpi_release( signature->s );
351
352 return LIBSPECTRUM_ERROR_NONE;
353 }
354
355 #endif /* #ifdef HAVE_GCRYPT_H */
356