Author: bh
Date: 2007-07-18 16:10:27 +0200 (Wed, 18 Jul 2007)
New Revision: 272
Modified:
trunk/openvas-server/ChangeLog
trunk/openvas-server/openvasd/openvas-check-signature.c
Log:
* openvasd/openvas-check-signature.c: Use GnuTLS instead of
OpenSSL. See comments in the file for things that could be done
better.
(print_tls_error, map_file, hexdecode): New. Helper functions.
(generate_signature, verify_signature): Use GnuTLS instead of
OpenSSL. Also, both functions now have an additional parameter
for the keyfile/certfile to use so that their filenames are no
longer hard wired.
(main): Add command line arguments to specifiy the key or
certificat to use when signing or verifying. Pass those filenames
to generate_signature and verify_signature.
Modified: trunk/openvas-server/ChangeLog
===================================================================
--- trunk/openvas-server/ChangeLog 2007-07-17 19:06:10 UTC (rev 271)
+++ trunk/openvas-server/ChangeLog 2007-07-18 14:10:27 UTC (rev 272)
@@ -1,3 +1,17 @@
+2007-07-18 Bernhard Herzog <[EMAIL PROTECTED]>
+
+ * openvasd/openvas-check-signature.c: Use GnuTLS instead of
+ OpenSSL. See comments in the file for things that could be done
+ better.
+ (print_tls_error, map_file, hexdecode): New. Helper functions.
+ (generate_signature, verify_signature): Use GnuTLS instead of
+ OpenSSL. Also, both functions now have an additional parameter
+ for the keyfile/certfile to use so that their filenames are no
+ longer hard wired.
+ (main): Add command line arguments to specifiy the key or
+ certificat to use when signing or verifying. Pass those filenames
+ to generate_signature and verify_signature.
+
2007-07-04 Bernhard Herzog <[EMAIL PROTECTED]>
* openvasd/plugs_hash.c (plugins_hash): Handle errors from
Modified: trunk/openvas-server/openvasd/openvas-check-signature.c
===================================================================
--- trunk/openvas-server/openvasd/openvas-check-signature.c 2007-07-17
19:06:10 UTC (rev 271)
+++ trunk/openvas-server/openvasd/openvas-check-signature.c 2007-07-18
14:10:27 UTC (rev 272)
@@ -27,89 +27,159 @@
*
*/
+/* FIXME: The code here is mostly a duplicate of code in
+ * openvas-libnasl/nasl/nasl_crypto2.c. The main difference is that the
+ * signatures dealt with here are detached, whereas the signatures
+ * handled by nasl_crypto2.c are part of the signed file.
+ *
+ * Also, the original OpenSSL code in this file was probably better at
+ * handling larger files. The new code read the file to sign or verify
+ * completely into memory which may be inefficient for large files.
+ *
+ * Before something is done about it, OpenVAS needs to decide how to
+ * deal with signed files in general.
+ */
+
#include <includes.h>
-#ifdef HAVE_SSL
-#include <openssl/bn.h>
-#include <openssl/dh.h>
-#include <openssl/evp.h>
-#include <openssl/blowfish.h>
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
-/*
+void
+print_tls_error(char *txt, int err)
+{
+ fprintf(stderr, "%s: %s (%d)\n", txt, gnutls_strerror(err), err);
+}
+
+gnutls_datum_t
+map_file(const char * filename)
+{
+ FILE *f;
+ gnutls_datum loaded_file = { NULL, 0 };
+ long filelen;
+ void *ptr;
+
+ if (!(f = fopen(filename, "r"))
+ || fseek(f, 0, SEEK_END) != 0
+ || (filelen = ftell(f)) < 0
+ || fseek(f, 0, SEEK_SET) != 0
+ || !(ptr = emalloc((size_t) filelen))
+ || fread(ptr, 1, (size_t) filelen, f) < (size_t) filelen)
+ {
+ return loaded_file;
+ }
+
+ loaded_file.data = ptr;
+ loaded_file.size = (unsigned int) filelen;
+ return loaded_file;
+}
+
+static ptrdiff_t
+hexdecode(unsigned char *binary, const unsigned char *hex, size_t fromlen)
+{
+ char temp[3] = {0, 0, 0};
+ unsigned char * to = binary;
+ const unsigned char * from = hex;
+
+ while ((from - hex) < fromlen - 1)
+ {
+ temp[0] = from[0];
+ temp[1] = from[1];
+ *to = strtoul(temp, NULL, 16);
+ to += 1;
+ from += 2;
+ }
+
+ return to - binary;
+}
+
+
+/*
* Signs a given file
*/
-int generate_signature(char * filename)
+static int
+generate_signature(char * keyfilename, char * filename)
{
- RSA * rsa = NULL;
- FILE * fp = fopen(OPENVASD_STATEDIR "/openvas_org.priv.pem", "r");
- unsigned char * result;
- unsigned int len;
- int i;
- unsigned char md[SHA_DIGEST_LENGTH+1];
- int be_len;
+ int result = -1;
+ int i;
+ int be_len;
+ gnutls_datum_t pem = {NULL, 0};
+ gnutls_datum_t script = {NULL, 0};
+ gnutls_x509_privkey_t privkey = NULL;
+ unsigned char* signature = NULL;
+ size_t signature_size = 0;
+ int err;
- SHA_CTX ctx;
- int fd;
- int n;
- char buf[1024];
- struct stat st;
+ err = gnutls_x509_privkey_init(&privkey);
+ if (err)
+ {
+ print_tls_error("gnutls_x509_privkey_init", err);
+ goto fail;
+ }
+ pem = map_file(keyfilename);
+ if (!pem.data)
+ goto fail;
- SHA1_Init(&ctx);
+ err = gnutls_x509_privkey_import(privkey, &pem, GNUTLS_X509_FMT_PEM);
+ if (err)
+ {
+ print_tls_error("gnutls_x509_privkey_import", err);
+ goto fail;
+ }
- fd = open(filename, O_RDONLY);
- if ( fd < 0 )
- {
- fprintf(stderr, "open(%s) : %s\n", filename, strerror(errno));
- return -1;
- }
+ script = map_file(filename);
+ if (!script.data)
+ {
+ goto fail;
+ }
- fstat(fd, &st);
- bzero(buf, sizeof(buf));
- while ( ( n = read(fd, buf, sizeof(buf))) > 0 )
- {
- SHA1_Update(&ctx, buf, n);
- }
- /* Add the size of the file at the end of the message */
- be_len = htonl(st.st_size);
- SHA1_Update(&ctx, &be_len, sizeof(be_len));
- SHA1_Final(md, &ctx);
- close(fd);
-
+ /* append the size of the file at the end of the script */
+ script.data = erealloc(script.data, script.size + sizeof(be_len));
+ be_len = htonl(script.size);
+ memcpy(script.data + script.size, &be_len, sizeof(be_len));
+ script.size += sizeof(be_len);
+ /* call gnutls_x509_privkey_sign_data twice: once to determine the
+ * size of the signature and then again to actually create the
+ * signature */
+ err = gnutls_x509_privkey_sign_data(privkey, GNUTLS_DIG_SHA1, 0, &script,
+ signature, &signature_size);
+ if (err != GNUTLS_E_SHORT_MEMORY_BUFFER)
+ {
+ print_tls_error("gnutls_x509_privkey_sign_data", err);
+ goto fail;
+ }
- if ( fp == NULL )
- {
- perror("open ");
- return -1;
- }
-
- rsa = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
- fclose(fp);
- if ( rsa == NULL )
- {
- fprintf(stderr, "PEM_read_RSAPrivateKey() failed\n");
- return -1;
- }
+ signature = emalloc(signature_size);
+ err = gnutls_x509_privkey_sign_data(privkey, GNUTLS_DIG_SHA1, 0, &script,
+ signature, &signature_size);
+ if (err)
+ {
+ print_tls_error("gnutls_x509_privkey_sign_data", err);
+ goto fail;
+ }
- len = RSA_size(rsa);
- result = emalloc(len);
-
- RSA_sign(NID_sha1, md, SHA_DIGEST_LENGTH, result, &len, rsa);
- for ( i = 0 ; i < len ; i ++ )
- {
- printf("%.2x", result[i]);
- }
- printf("\n");
- fflush(stdout);
- efree(&result);
- RSA_free(rsa);
-
- return 0;
+ /* print the signature to stdout in hexadecimal */
+ for (i = 0; i < signature_size; i++)
+ {
+ printf("%.2x", signature[i]);
+ }
+ printf("\n");
+
+ result = 0;
+
+ fail:
+ efree(&pem.data);
+ efree(&script.data);
+ efree(&signature);
+ gnutls_x509_privkey_deinit(privkey);
+
+ return result;
}
-
-/*
+
+/*
* Verify an archive signature
*
* Returns :
@@ -117,128 +187,189 @@
* 0 : if the signature matches
* 1 : if the signature does NOT match
*/
-int verify_signature(char * filename, char * signature)
+static int
+verify_signature(char * certfilename, char * filename, char * sigfilename)
{
- unsigned char md[SHA_DIGEST_LENGTH+1];
- RSA * rsa = NULL;
- FILE * fp = fopen(OPENVASD_STATEDIR "/openvas_org.pem", "r");
+ int be_len;
+ gnutls_x509_crt_t cert = NULL;
+ gnutls_datum_t pem = {NULL, 0};
+ gnutls_datum_t script = {NULL, 0};
+ gnutls_datum_t signature = {NULL, 0};
+ int result = -1;
+ int err;
- char sig[16384];
- unsigned char bin_sig[8192];
- int binsz = 0;
+ pem = map_file(certfilename);
+ if (!pem.data)
+ goto fail;
- int i, sig_len = 0, res = -1, be_len;
- FILE * sigfile = fopen(signature, "r");
+ err = gnutls_x509_crt_init(&cert);
+ if (err)
+ {
+ print_tls_error("gnutls_x509_crt_init", err);
+ goto fail;
+ }
- SHA_CTX ctx;
- struct stat st;
- int fd;
- char buf[1024];
- int n;
+ err = gnutls_x509_crt_import(cert, &pem, GNUTLS_X509_FMT_PEM);
+ if (err)
+ {
+ print_tls_error("gnutls_x509_crt_import", err);
+ goto fail;
+ }
+ script = map_file(filename);
+ if (!script.data)
+ {
+ goto fail;
+ }
- if ( fp == NULL )
- {
- fprintf(stderr, "Open %s/openvas_org.pem : %s\n", OPENVASD_STATEDIR,
strerror(errno));
- return -1;
- }
+ /* Make room for the size of the file at the end of the script and
+ * append the size */
+ script.data = erealloc(script.data, script.size + sizeof(be_len));
+ be_len = htonl(script.size);
+ memcpy(script.data + script.size, &be_len, sizeof(be_len));
+ script.size += sizeof(be_len);
- /* No signature - fail */
- if ( sigfile == NULL )
- {
- fprintf(stderr, "Open %s : %s\n", signature, strerror(errno));
- return 1;
- }
+ /* read and decode the hex signature. Decoding can be done in place
+ * because the binary signature is always shorter than its hexadecimal
+ * representation. */
+ signature = map_file(sigfilename);
+ if (!signature.data)
+ {
+ goto fail;
+ }
+ signature.size = hexdecode(signature.data, signature.data, signature.size);
- fgets(sig, sizeof(sig) - 1, sigfile);
- fclose(sigfile);
- sig[sizeof(sig) - 1] = '\0';
+ err = gnutls_x509_crt_verify_data(cert, 0, &script, &signature);
+ if (err < 0)
+ {
+ print_tls_error("gnutls_x509_crt_verify_data", err);
+ goto fail;
+ }
+ result = err == 1 ? 0 : 1;
- fd = open(filename, O_RDONLY);
- if ( fd < 0 )
- {
- fprintf(stderr, "open(%s) : %s\n", filename, strerror(errno));
- return 1;
- }
-
+ fail:
+ gnutls_x509_crt_deinit(cert);
+ efree(&script.data);
+ efree(&signature.data);
+ efree(&pem);
- fstat(fd, &st);
- SHA1_Init(&ctx);
- bzero(buf, sizeof(buf));
- while ( ( n = read(fd, buf, sizeof(buf)) ) > 0 )
- {
- SHA1_Update(&ctx, buf, n);
- }
+ return result;
- be_len = htonl(st.st_size);
- SHA1_Update(&ctx, &be_len, sizeof(be_len));
- SHA1_Final(md, &ctx);
- close(fd);
+}
- rsa = PEM_read_RSA_PUBKEY(fp, NULL, NULL, NULL);
- fclose(fp);
- if ( rsa == NULL ) return -1;
+int
+main(int argc, char ** argv)
+{
+ int do_sign = 0;
+ int do_print_usage = 0;
+ char * keyfile = NULL;
+ char * certfile = NULL;
+ int opt;
+ int option_index = 0;
+ struct option long_options[] =
+ {
+ {"help", no_argument, 0, 'h'},
+ {"certificate", required_argument, 0, 'c'},
+ {"key", required_argument, 0, 'k'},
+ {"sign", no_argument, 0, 's'},
+ {0, 0, 0, 0}
+ };
- sig_len = strlen(sig) - 1;
+ while ((opt = getopt_long(argc, argv, "c:hk:s", long_options, &option_index))
+ != -1)
+ {
+ switch (opt)
+ {
+ case 'c':
+ certfile = optarg;
+ break;
- for ( i = 0 ; i < sig_len ; i += 2 )
- {
- char t[3];
- strncpy(t, sig + i, 2);
- t[2] = '\0';
- bin_sig[binsz] = strtoul(t, NULL, 16);
- binsz ++;
- if ( binsz >= sizeof(bin_sig) ) goto err; /* Too long signature */
- }
-
-
+ case 'h':
+ do_print_usage = 1;
+ break;
- res = RSA_verify(NID_sha1, md, SHA_DIGEST_LENGTH, bin_sig, binsz, rsa);
- RSA_free(rsa);
- return res == 1 ? 0 : 1;
-
-err:
- RSA_free(rsa);
- return -1;
-
-}
+ case 'k':
+ keyfile = optarg;
+ break;
+ case 's':
+ do_sign = 1;
+ break;
-int main(int argc, char ** argv)
-{
- int do_sign = 0;
- if ( argc != 3 )
- {
- fprintf(stderr, "Usage: openvas-check-signature [-S] filename
[signaturefile]\n");
- exit(1);
- }
+ case '?':
+ fprintf(stderr, "unknown option or missing"
+ " parameter for option '%c'\n", opt);
+ return 1;
- nessus_SSL_init(NULL);
+ default:
+ fprintf(stderr, "option '%c' not implemented\n", opt);
+ return 1;
+ }
+ }
- if ( strcmp(argv[1], "-S") == 0 )
- do_sign ++;
+ if (do_print_usage)
+ {
+ fprintf(stderr,
+ "Usage: openvas-check-signature [options]"
+ " filename [signaturefile]\n");
+ fprintf(stderr, "Options:\n");
+ fprintf(stderr, " -h Print this help message\n");
+ fprintf(stderr, " -k keyfile File with private key for signature\n");
+ fprintf(stderr, " -c certfile File with certificate for signature"
+ " verificationi\n");
+ return 0;
+ }
- if ( do_sign == 0 )
- {
- if ( verify_signature(argv[1], argv[2]) <= 0 )
- exit(0);
+ nessus_SSL_init(NULL);
+
+ if (do_sign)
+ {
+ if (!keyfile)
+ {
+ fprintf(stderr, "Missing parameter -k required for"
+ " signature generation\n");
+ return 1;
+ }
+ if (optind >= argc)
+ {
+ fprintf(stderr, "missing filename parameter\n");
+ return 1;
+ }
+
+ generate_signature(keyfile, argv[optind]);
+ }
else
+ {
+ if (!certfile)
{
- printf("%s is not the valid signature for %s\n", argv[2], argv[1]);
- exit(1);
+ fprintf(stderr, "Missing parameter -c required for"
+ " signature verification\n");
+ return 1;
}
- }
- else {
- generate_signature(argv[2]);
+
+ if (optind + 1 >= argc)
+ {
+ fprintf(stderr, "for signature verification, a filename and the"
+ " signature filename must be given\n");
+ return 1;
}
- exit(0);
+ else
+ {
+ char * filename = argv[optind];
+ char * signaturefile = argv[optind + 1];
+
+ if (verify_signature(certfile, filename, signaturefile) == 0)
+ return 0;
+ else
+ {
+ fprintf(stderr, "%s is not the valid signature for %s\n",
+ signaturefile, filename);
+ return 1;
+ }
+ }
+ }
+
+ return 0;
}
-#else
-int main()
-{
- printf("openvas-check-signature: OpenSSL support has been disabled\n");
- exit(0);
-}
-#endif
_______________________________________________
Openvas-commits mailing list
[email protected]
http://lists.wald.intevation.org/mailman/listinfo/openvas-commits