2
* $Id: openvas-check-signature.c 272 2007-07-18 14:10:27Z bh $
3
* Description: generates/checks a signature for a given file.
5
* Authors: - Renaud Deraison <deraison@nessus.org> (Original pre-fork develoment)
6
* - Tim Brown <mailto:timb@openvas.org> (Initial fork)
7
* - Laban Mwangi <mailto:labanm@openvas.org> (Renaming work)
8
* - Tarik El-Yassem <mailto:tarik@openvas.org> (Headers section)
11
* Portions Copyright (C) 2006 Software in the Public Interest, Inc.
12
* Based on work Copyright (C) 1998 - 2006 Tenable Network Security, Inc.
14
* This program is free software; you can redistribute it and/or modify
15
* it under the terms of the GNU General Public License version 2,
16
* as published by the Free Software Foundation
18
* This program is distributed in the hope that it will be useful,
19
* but WITHOUT ANY WARRANTY; without even the implied warranty of
20
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21
* GNU General Public License for more details.
23
* You should have received a copy of the GNU General Public License
24
* along with this program; if not, write to the Free Software
25
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
30
/* FIXME: The code here is mostly a duplicate of code in
31
* openvas-libnasl/nasl/nasl_crypto2.c. The main difference is that the
32
* signatures dealt with here are detached, whereas the signatures
33
* handled by nasl_crypto2.c are part of the signed file.
35
* Also, the original OpenSSL code in this file was probably better at
36
* handling larger files. The new code read the file to sign or verify
37
* completely into memory which may be inefficient for large files.
39
* Before something is done about it, OpenVAS needs to decide how to
40
* deal with signed files in general.
44
#include <gnutls/gnutls.h>
45
#include <gnutls/x509.h>
49
print_tls_error(char *txt, int err)
51
fprintf(stderr, "%s: %s (%d)\n", txt, gnutls_strerror(err), err);
55
map_file(const char * filename)
58
gnutls_datum loaded_file = { NULL, 0 };
62
if (!(f = fopen(filename, "r"))
63
|| fseek(f, 0, SEEK_END) != 0
64
|| (filelen = ftell(f)) < 0
65
|| fseek(f, 0, SEEK_SET) != 0
66
|| !(ptr = emalloc((size_t) filelen))
67
|| fread(ptr, 1, (size_t) filelen, f) < (size_t) filelen)
72
loaded_file.data = ptr;
73
loaded_file.size = (unsigned int) filelen;
78
hexdecode(unsigned char *binary, const unsigned char *hex, size_t fromlen)
80
char temp[3] = {0, 0, 0};
81
unsigned char * to = binary;
82
const unsigned char * from = hex;
84
while ((from - hex) < fromlen - 1)
88
*to = strtoul(temp, NULL, 16);
101
generate_signature(char * keyfilename, char * filename)
106
gnutls_datum_t pem = {NULL, 0};
107
gnutls_datum_t script = {NULL, 0};
108
gnutls_x509_privkey_t privkey = NULL;
109
unsigned char* signature = NULL;
110
size_t signature_size = 0;
113
err = gnutls_x509_privkey_init(&privkey);
116
print_tls_error("gnutls_x509_privkey_init", err);
120
pem = map_file(keyfilename);
124
err = gnutls_x509_privkey_import(privkey, &pem, GNUTLS_X509_FMT_PEM);
127
print_tls_error("gnutls_x509_privkey_import", err);
131
script = map_file(filename);
137
/* append the size of the file at the end of the script */
138
script.data = erealloc(script.data, script.size + sizeof(be_len));
139
be_len = htonl(script.size);
140
memcpy(script.data + script.size, &be_len, sizeof(be_len));
141
script.size += sizeof(be_len);
143
/* call gnutls_x509_privkey_sign_data twice: once to determine the
144
* size of the signature and then again to actually create the
146
err = gnutls_x509_privkey_sign_data(privkey, GNUTLS_DIG_SHA1, 0, &script,
147
signature, &signature_size);
148
if (err != GNUTLS_E_SHORT_MEMORY_BUFFER)
150
print_tls_error("gnutls_x509_privkey_sign_data", err);
154
signature = emalloc(signature_size);
155
err = gnutls_x509_privkey_sign_data(privkey, GNUTLS_DIG_SHA1, 0, &script,
156
signature, &signature_size);
159
print_tls_error("gnutls_x509_privkey_sign_data", err);
163
/* print the signature to stdout in hexadecimal */
164
for (i = 0; i < signature_size; i++)
166
printf("%.2x", signature[i]);
176
gnutls_x509_privkey_deinit(privkey);
183
* Verify an archive signature
186
* -1 : if an error occured
187
* 0 : if the signature matches
188
* 1 : if the signature does NOT match
191
verify_signature(char * certfilename, char * filename, char * sigfilename)
194
gnutls_x509_crt_t cert = NULL;
195
gnutls_datum_t pem = {NULL, 0};
196
gnutls_datum_t script = {NULL, 0};
197
gnutls_datum_t signature = {NULL, 0};
201
pem = map_file(certfilename);
205
err = gnutls_x509_crt_init(&cert);
208
print_tls_error("gnutls_x509_crt_init", err);
212
err = gnutls_x509_crt_import(cert, &pem, GNUTLS_X509_FMT_PEM);
215
print_tls_error("gnutls_x509_crt_import", err);
219
script = map_file(filename);
225
/* Make room for the size of the file at the end of the script and
227
script.data = erealloc(script.data, script.size + sizeof(be_len));
228
be_len = htonl(script.size);
229
memcpy(script.data + script.size, &be_len, sizeof(be_len));
230
script.size += sizeof(be_len);
232
/* read and decode the hex signature. Decoding can be done in place
233
* because the binary signature is always shorter than its hexadecimal
235
signature = map_file(sigfilename);
240
signature.size = hexdecode(signature.data, signature.data, signature.size);
242
err = gnutls_x509_crt_verify_data(cert, 0, &script, &signature);
245
print_tls_error("gnutls_x509_crt_verify_data", err);
249
result = err == 1 ? 0 : 1;
252
gnutls_x509_crt_deinit(cert);
254
efree(&signature.data);
263
main(int argc, char ** argv)
266
int do_print_usage = 0;
267
char * keyfile = NULL;
268
char * certfile = NULL;
270
int option_index = 0;
271
struct option long_options[] =
273
{"help", no_argument, 0, 'h'},
274
{"certificate", required_argument, 0, 'c'},
275
{"key", required_argument, 0, 'k'},
276
{"sign", no_argument, 0, 's'},
280
while ((opt = getopt_long(argc, argv, "c:hk:s", long_options, &option_index))
302
fprintf(stderr, "unknown option or missing"
303
" parameter for option '%c'\n", opt);
307
fprintf(stderr, "option '%c' not implemented\n", opt);
315
"Usage: openvas-check-signature [options]"
316
" filename [signaturefile]\n");
317
fprintf(stderr, "Options:\n");
318
fprintf(stderr, " -h Print this help message\n");
319
fprintf(stderr, " -k keyfile File with private key for signature\n");
320
fprintf(stderr, " -c certfile File with certificate for signature"
325
nessus_SSL_init(NULL);
331
fprintf(stderr, "Missing parameter -k required for"
332
" signature generation\n");
337
fprintf(stderr, "missing filename parameter\n");
341
generate_signature(keyfile, argv[optind]);
347
fprintf(stderr, "Missing parameter -c required for"
348
" signature verification\n");
352
if (optind + 1 >= argc)
354
fprintf(stderr, "for signature verification, a filename and the"
355
" signature filename must be given\n");
360
char * filename = argv[optind];
361
char * signaturefile = argv[optind + 1];
363
if (verify_signature(certfile, filename, signaturefile) == 0)
367
fprintf(stderr, "%s is not the valid signature for %s\n",
368
signaturefile, filename);