Author: bh
Date: 2007-07-17 15:53:45 +0200 (Tue, 17 Jul 2007)
New Revision: 267
Modified:
trunk/openvas-libnasl/ChangeLog
trunk/openvas-libnasl/nasl/nasl_crypto2.c
Log:
* nasl/nasl_crypto2.c: Use GnuTLS/libgcrypt instead of OpenSSL.
Note the incompatible changes in rsa_sign and
verify_script_signature.
(print_tls_error, print_gcrypt_error): New. Helper functions to
print error messages.
(mpi_from_string, mpi_from_named_parameter, set_mpi_retc): New.
Helper functions to handle MPIs
(extract_mpi_from_sexp, set_retc_from_sexp): New. Helper functions
to handle gcrypt s-expressions.
(nasl_load_privkey_param, nasl_sexp_from_privkey): New. Helper
functions to handle private keys.
(calc_dh_public, calc_dh_key): New. Helper functions for
diffie-hellman
(hexdecode): New. Helper function to decode a hex string.
(nasl_bn_cmp, nasl_bn_random, nasl_pem_to)
(nasl_dh_generate_key, nasl_dh_compute_key)
(nasl_rsa_public_decrypt, nasl_rsa_sign, nasl_dsa_do_verify)
(nasl_dsa_do_sign, nasl_bf_cbc): Use GnuTLS/libgcrypt instead of
OpenSSL. nasl_rsa_sign has different parameters now (see comments
in the code).
(nasl_bf_cbc_encrypt, nasl_bf_cbc_decrypt): Adapt to changes in
nasl_bf_cbc
(map_file): Return the data as a gnutls_datum_t.
(generate_signed_script, verify_script_signature): Use
GnuTLS/libgcrypt instead of OpenSSL. verify_script_signature now
requires an x509 certificate instead of just an RSA key.
Modified: trunk/openvas-libnasl/ChangeLog
===================================================================
--- trunk/openvas-libnasl/ChangeLog 2007-07-12 19:26:09 UTC (rev 266)
+++ trunk/openvas-libnasl/ChangeLog 2007-07-17 13:53:45 UTC (rev 267)
@@ -1,3 +1,32 @@
+2007-07-17 Bernhard Herzog <[EMAIL PROTECTED]>
+
+ * nasl/nasl_crypto2.c: Use GnuTLS/libgcrypt instead of OpenSSL.
+ Note the incompatible changes in rsa_sign and
+ verify_script_signature.
+ (print_tls_error, print_gcrypt_error): New. Helper functions to
+ print error messages.
+ (mpi_from_string, mpi_from_named_parameter, set_mpi_retc): New.
+ Helper functions to handle MPIs
+ (extract_mpi_from_sexp, set_retc_from_sexp): New. Helper functions
+ to handle gcrypt s-expressions.
+ (nasl_load_privkey_param, nasl_sexp_from_privkey): New. Helper
+ functions to handle private keys.
+ (calc_dh_public, calc_dh_key): New. Helper functions for
+ diffie-hellman
+ (hexdecode): New. Helper function to decode a hex string.
+ (nasl_bn_cmp, nasl_bn_random, nasl_pem_to)
+ (nasl_dh_generate_key, nasl_dh_compute_key)
+ (nasl_rsa_public_decrypt, nasl_rsa_sign, nasl_dsa_do_verify)
+ (nasl_dsa_do_sign, nasl_bf_cbc): Use GnuTLS/libgcrypt instead of
+ OpenSSL. nasl_rsa_sign has different parameters now (see comments
+ in the code).
+ (nasl_bf_cbc_encrypt, nasl_bf_cbc_decrypt): Adapt to changes in
+ nasl_bf_cbc
+ (map_file): Return the data as a gnutls_datum_t.
+ (generate_signed_script, verify_script_signature): Use
+ GnuTLS/libgcrypt instead of OpenSSL. verify_script_signature now
+ requires an x509 certificate instead of just an RSA key.
+
2007-07-09 Bernhard Herzog <[EMAIL PROTECTED]>
* nasl/nasl_crypto.c (nasl_gcrypt_hash, nasl_hash): New. Helper
Modified: trunk/openvas-libnasl/nasl/nasl_crypto2.c
===================================================================
--- trunk/openvas-libnasl/nasl/nasl_crypto2.c 2007-07-12 19:26:09 UTC (rev
266)
+++ trunk/openvas-libnasl/nasl/nasl_crypto2.c 2007-07-17 13:53:45 UTC (rev
267)
@@ -17,10 +17,14 @@
*
*
*/
+
/*
- * This file contains all the call to OpenSSL functions needed by SSH protocol
+ * This file contains all the crypto functionality needed by the SSH protocol
*/
#include <includes.h>
+#include <gcrypt.h>
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
#include "nasl_tree.h"
#include "nasl_global_ctxt.h"
@@ -39,520 +43,1054 @@
#define MAP_FAILED (void*)(-1)
#endif
-#ifdef HAVE_SSL
-#include <openssl/bn.h>
-#include <openssl/dh.h>
-#include <openssl/evp.h>
-
-#include <openssl/blowfish.h>
-
#define INTBLOB_LEN 20
#define SIGBLOB_LEN (2*INTBLOB_LEN)
-tree_cell * nasl_bn_cmp(lex_ctxt* lexic)
+/* prints a GnuTLS error. The parameter err should be the GnuTLS error
+ * code */
+void
+print_tls_error(lex_ctxt * lexic, char *txt, int err)
{
- char *s1 = NULL,*s2 = NULL;
- tree_cell *retc = NULL;
- BIGNUM *key1 = NULL, *key2 = NULL;
- int vn;
- long sz1, sz2;
+ nasl_perror(lexic, "%s: %s (%d)\n", txt, gnutls_strerror(err), err);
+}
+/* prints a libgcrypt error. The parameter err should be the libgcrypt
+ * error code */
+void
+print_gcrypt_error(lex_ctxt * lexic, char *function, int err)
+{
+ nasl_perror(lexic,
+ "%s failed: %s/%s\n",
+ function, gcry_strsource(err), gcry_strerror(err));
+}
+
+/* Converts a string to a gcry_mpi_t. The string of len bytes at data
+ * should contain the MPI as an unsigned int in bigendian form
+ * (libgcrypt's GCRYMPI_FMT_USG). The new MPI object is stored in dest.
+ * The parameters function and parameter are used in error messages to
+ * indicate the nasl function and nasl parameter name of the MPI. The
+ * lexic parameter is passed through to the error reporting functions.
+ *
+ * The function return 0 on success and -1 on failure.
+ */
+static int
+mpi_from_string(lex_ctxt* lexic, gcry_mpi_t *dest, void *data, size_t len,
+ const char *parameter, const char* function)
+{
+ gcry_error_t err;
+ unsigned char* buffer = data;
+
+ if (len < 0)
+ return -1;
+
+ err = gcry_mpi_scan(dest, GCRYMPI_FMT_USG, buffer, len, NULL);
+
+ if (err)
+ {
+ nasl_perror(lexic,
+ "%s(): gcry_mpi_scan failed for %s: %s/%s\n",
+ function, parameter, gcry_strsource(err), gcry_strerror(err));
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Converts a named nasl parameter to a gcry_mpi_t. The new MPI object
+ * is stored in dest. The parameter parameter is the name of the
+ * parameter to be taken from lexic. The parameter function is used in
+ * error messages to indicate the name of the nasl function.
+ *
+ * The function return 0 on success and -1 on failure.
+ */
+static int
+mpi_from_named_parameter(lex_ctxt* lexic, gcry_mpi_t *dest,
+ const char* parameter, const char *function)
+{
+ long size;
+ char *s;
+
+ s = get_str_local_var_by_name(lexic, parameter);
+ size = get_var_size_by_name(lexic, parameter);
+
+ if (!s)
+ return -1;
+
+ return mpi_from_string(lexic, dest, s, size, parameter, function);
+}
+
+/* Sets the return value in retc from the MPI mpi. The MPI is converted
+ * to a byte string as an unsigned int in bigendian form (libgcrypts
+ * GCRYMPI_FMT_USG format). If first byte in the string has it's most
+ * significant bit set, i.e. if it would be considered negative when
+ * interpreted as two's-complement representation, a null-byte is
+ * prepended to make sure the number is always considered positive.
+ *
+ * The function return 0 on success and -1 on failure.
+ */
+static int
+set_mpi_retc(tree_cell *retc, gcry_mpi_t mpi)
+{
+ unsigned char *buffer = NULL;
+ size_t size;
+ int extra;
+
+ gcry_mpi_aprint(GCRYMPI_FMT_USG, &buffer, &size, mpi);
+ if (!buffer)
+ return -1;
+
+ if (buffer[0] & 0x80)
+ extra = 1;
+ else
+ extra = 0;
+
+ retc->x.str_val = emalloc(size + extra);
+ retc->x.str_val[0] = '\0';
+ memcpy(retc->x.str_val + extra, buffer, size);
+ retc->size = size + extra;
+
+ gcry_free(buffer);
+
+ return 0;
+}
+
+/* nasl function
+ *
+ * bn_cmp(key1:MPI1, key2:MPI2)
+ *
+ * Compares the MPIs key1 and key2 (given as binary strings). Returns
+ * -1 if key1 < key2, 0 if key1 == key2 and +1 if key1 > key2.
+ */
+tree_cell *
+nasl_bn_cmp(lex_ctxt* lexic)
+{
+ tree_cell *retc = NULL;
+ gcry_mpi_t key1 = NULL, key2 = NULL;
+
retc = emalloc(sizeof(tree_cell));
retc->ref_count = 1;
retc->type = CONST_INT;
retc->x.i_val = 1;
- vn = array_max_index(&lexic->ctx_vars);
- /* key1 */
- s1 = get_str_local_var_by_name(lexic, "key1");
- sz1 = get_var_size_by_name(lexic, "key1");
+ if (mpi_from_named_parameter(lexic, &key1, "key1", "nasl_bn_cmp") < 0)
+ goto fail;
+ if (mpi_from_named_parameter(lexic, &key2, "key2", "nasl_bn_cmp") < 0)
+ goto fail;
- /* key2 */
- s2 = get_str_local_var_by_name(lexic, "key2");
- sz2 = get_var_size_by_name(lexic, "key2");
+ retc->x.i_val = gcry_mpi_cmp(key1, key2);
- if ( s1 == NULL || s2 == NULL )
- goto fail;
-
- key1 = BN_new();
- key2 = BN_new();
+ /* make sure the return value is one of -1, 0, +1 */
+ if (retc->x.i_val > 0)
+ retc->x.i_val = 1;
+ if (retc->x.i_val < 0)
+ retc->x.i_val = -1;
- if (BN_bin2bn((const unsigned char*)s1, sz1, key1) == 0)
- goto fail;
- if (BN_bin2bn((const unsigned char*)s2, sz2, key2) == 0)
- goto fail;
-
- retc->x.i_val = BN_cmp(key1,key2);
-
fail:
- BN_free(key1);
- BN_free(key2);
+ gcry_mpi_release(key1);
+ gcry_mpi_release(key2);
return retc;
}
-
-tree_cell * nasl_bn_random(lex_ctxt* lexic)
+/* nasl function
+ *
+ * bn_random(need:numBits)
+ *
+ * Returns an MPI as a string with need bits of random data.
+ */
+tree_cell *
+nasl_bn_random(lex_ctxt* lexic)
{
- char *s1 = NULL;
- tree_cell *retc = NULL;
- BIGNUM *key = NULL;
- long need, needlen, s1len;
- int len;
+ tree_cell *retc = NULL;
+ gcry_mpi_t key = NULL;
+ long need;
retc = alloc_tree_cell(0, NULL);
retc->type = CONST_DATA;
-
- /* p bignum */
+
+ /* number of random bits */
need = get_int_local_var_by_name(lexic, "need", 0);
- needlen = get_var_size_by_name(lexic, "need");
- key = BN_new();
+ key = gcry_mpi_new(0);
if (!key)
goto fail;
-
- if (!BN_rand(key, need, 0, 0))
- goto fail;
- s1len = BN_num_bytes(key);
- s1 = emalloc(s1len);
- if (s1 == NULL)
- goto fail;
+ gcry_mpi_randomize(key, need, GCRY_STRONG_RANDOM);
- BN_bn2bin(key, (unsigned char*)s1);
+ if (set_mpi_retc(retc, key) >= 0)
+ goto ret;
- if (s1[0] & 0x80)
- len = 1;
- else
- len = 0;
- retc->x.str_val = emalloc (s1len+len);
- retc->x.str_val[0] = '\0';
- memcpy(retc->x.str_val+len, s1, s1len);
- retc->size = s1len + len;
-
- goto ret;
-
-fail:
+ fail:
retc->size = 0;
retc->x.str_val = emalloc(0);
-ret:
- BN_free(key);
+ ret:
+ gcry_mpi_release(key);
return retc;
-
}
+/* Loads a private key from a string. The string is taken from the nasl
+ * parameter whose name is given by priv_name. The passphrase_name is
+ * the name of the parameter holding the passphrase if any. The string
+ * with the key must be in PEM format.
+ *
+ * The function returns the GnuTLS private key object on success, NULL
+ * on failure.
+ */
+static gnutls_x509_privkey_t
+nasl_load_privkey_param(lex_ctxt* lexic, const char * priv_name,
+ const char* passphrase_name)
+{
+ char *priv = NULL, *passphrase = NULL;
+ long privlen, passphraselen;
+ gnutls_x509_privkey_t privkey = NULL;
+ gnutls_datum_t pem;
+ int err;
-tree_cell * nasl_pem_to(lex_ctxt* lexic, int type)
+ /* PEM encoded privkey */
+ priv = get_str_local_var_by_name(lexic, priv_name);
+ privlen = get_var_size_by_name(lexic, priv_name);
+
+ /* passphrase */
+ passphrase = get_str_local_var_by_name(lexic, passphrase_name);
+ passphraselen = get_var_size_by_name(lexic, passphrase_name);
+
+ pem.data = (unsigned char*)priv;
+ pem.size = privlen;
+
+ err = gnutls_x509_privkey_init(&privkey);
+ if (err)
+ {
+ print_tls_error(lexic, "gnutls_x509_privkey_init", err);
+ goto fail;
+ }
+
+ if (passphraselen == 0 || passphrase[0] == 0)
+ {
+ err = gnutls_x509_privkey_import(privkey, &pem, GNUTLS_X509_FMT_PEM);
+ if (err)
+ {
+ print_tls_error(lexic, "gnutls_x509_privkey_import", err);
+ goto fail;
+ }
+ }
+ else
+ {
+ err = gnutls_x509_privkey_import_pkcs8(privkey, &pem,
GNUTLS_X509_FMT_PEM,
+ passphrase, 0);
+ if (err)
+ {
+ print_tls_error(lexic, "gnutls_x509_privkey_import_pkcs8", err);
+ goto fail;
+ }
+ }
+
+
+ return privkey;
+
+ fail:
+ gnutls_x509_privkey_deinit(privkey);
+ return NULL;
+}
+
+/* Implements the nasl functions pem_to_rsa and pem_to_dsa. */
+tree_cell *
+nasl_pem_to(lex_ctxt* lexic, int type)
{
- char *s1 = NULL, *priv = NULL, *passphrase = NULL;
- tree_cell *retc = NULL;
- RSA * rsa = NULL;
- DSA * dsa = NULL;
- BIGNUM * key = NULL;
- BIO * bio = NULL;
- long privlen, plen, s1len;
- int len;
+ tree_cell *retc = NULL;
+ gnutls_x509_privkey_t privkey = NULL;
+ gcry_mpi_t key = NULL;
+ int err;
- if ( check_authenticated(lexic) < 0 ) return FAKE_CELL;
+ if (check_authenticated(lexic) < 0)
+ return FAKE_CELL;
retc = alloc_tree_cell(0, NULL);
retc->type = CONST_DATA;
-
- /* priv bignum */
- priv = get_str_local_var_by_name(lexic, "priv");
- privlen = get_var_size_by_name(lexic, "priv");
- if ( priv == NULL )
- goto fail;
-
- /* priv bignum */
- passphrase = get_str_local_var_by_name(lexic, "passphrase");
- plen = get_var_size_by_name(lexic, "passphrase");
+ privkey = nasl_load_privkey_param(lexic, "priv", "passphrase");
+ if (!privkey)
+ goto fail;
- bio = BIO_new_mem_buf(priv, privlen);
- if (!bio)
- goto fail;
-
if (!type)
{
- rsa = PEM_read_bio_RSAPrivateKey(bio, NULL, NULL, passphrase);
- if (!rsa)
- goto fail;
- key = rsa->d;
+ gnutls_datum_t m, e, d, p, q, u;
+ err = gnutls_x509_privkey_export_rsa_raw(privkey, &m, &e, &d, &p, &q,
&u);
+ if (err)
+ {
+ print_tls_error(lexic, "gnutls_x509_privkey_export_rsa_raw", err);
+ goto fail;
+ }
+
+ err = mpi_from_string(lexic, &key, d.data, d.size, "rsa d",
+ "nasl_pem_to");
+ gnutls_free(m.data);
+ gnutls_free(e.data);
+ gnutls_free(d.data);
+ gnutls_free(p.data);
+ gnutls_free(q.data);
+ gnutls_free(u.data);
+
+ if (err < 0)
+ goto fail;
}
else
{
- dsa = PEM_read_bio_DSAPrivateKey(bio, NULL, NULL, passphrase);
- if (!dsa)
- goto fail;
- key = dsa->priv_key;
+ gnutls_datum_t p, q, g, y, x;
+ err = gnutls_x509_privkey_export_dsa_raw(privkey, &p, &q, &g, &y, &x);
+ if (err)
+ {
+ print_tls_error(lexic, "gnutls_x509_privkey_export_dsa_raw", err);
+ goto fail;
+ }
+
+ err = mpi_from_string(lexic, &key, x.data, x.size, "dsa x",
+ "nasl_pem_to");
+
+ gnutls_free(p.data);
+ gnutls_free(q.data);
+ gnutls_free(g.data);
+ gnutls_free(y.data);
+ gnutls_free(x.data);
+
+ if (err < 0)
+ goto fail;
}
-
- s1len = BN_num_bytes(key);
- s1 = emalloc(s1len);
- if (s1 == NULL)
- goto fail;
- BN_bn2bin(key, (unsigned char*)s1);
-
- if (s1[0] & 0x80)
- len = 1;
- else
- len = 0;
- retc->x.str_val = emalloc (s1len+len);
- retc->x.str_val[0] = '\0';
- memcpy(retc->x.str_val+len, s1, s1len);
- retc->size = s1len + len;
+ if (set_mpi_retc(retc, key) >= 0)
+ goto ret;
- goto ret;
-
fail:
retc->size = 0;
retc->x.str_val = emalloc(0);
ret:
- BIO_free(bio);
- RSA_free(rsa);
- DSA_free(dsa);
+ gcry_mpi_release(key);
+ gnutls_x509_privkey_deinit(privkey);
return retc;
-
}
-tree_cell * nasl_pem_to_rsa(lex_ctxt* lexic)
+/* nasl function
+ *
+ * pem_to_rsa(priv:PEM, passphrase:PASSPHRASE)
+ *
+ * Reads the private key from the string priv which contains a private
+ * RSA key in PEM format. Passphrase is the passphrase needed to
+ * decrypt the private key. The function returns the parameter "d" of
+ * the RSA key as an MPI.
+ */
+tree_cell *
+nasl_pem_to_rsa(lex_ctxt* lexic)
{
return nasl_pem_to(lexic, 0);
}
-
-tree_cell * nasl_pem_to_dsa(lex_ctxt* lexic)
+/* nasl function
+ *
+ * pem_to_dsa(priv:PEM, passphrase:PASSPHRASE)
+ *
+ * Reads the private key from the string priv which contains a private
+ * DSA key in PEM format. Passphrase is the passphrase needed to
+ * decrypt the private key. The function returns the parameter "x" of
+ * the DSA key as an MPI.
+ */
+tree_cell *
+nasl_pem_to_dsa(lex_ctxt* lexic)
{
return nasl_pem_to(lexic, 1);
}
-tree_cell * nasl_dh_generate_key(lex_ctxt* lexic)
+/* compute the diffie hellman public key. Neither GnuTLS nor Libgcrypt
+ * contain a direct counterpart to OpenSSL's DH_generate_key, so we
+ * implement it ourselves. This function was copied from from gnutls
+ * and adapted to use gcrypt directly and to use a private key given as
+ * parameter to the function.
+ *
+ * The function returns the key on success and NULL on failure.
+ */
+static gcry_mpi_t
+calc_dh_public(gcry_mpi_t g, gcry_mpi_t prime, gcry_mpi_t priv)
{
- char *s1 = NULL,*s2 = NULL,*s3 = NULL,*pub = NULL;
- tree_cell *retc = NULL;
- DH *dh = NULL;
- long sz1, sz2, sz3, pubsize;
- int len;
+ gcry_mpi_t e;
- retc = alloc_tree_cell(0, NULL);
- retc->type = CONST_DATA;
-
- /* p bignum */
- s1 = get_str_local_var_by_name(lexic, "p");
- sz1 = get_var_size_by_name(lexic, "p");
-
- /* g bignum */
- s2 = get_str_local_var_by_name(lexic, "g");
- sz2 = get_var_size_by_name(lexic, "g");
+ e = gcry_mpi_new(gcry_mpi_get_nbits(prime));
+ if (e == NULL)
+ {
+ return NULL;
+ }
- /* priv key bignum */
- s3 = get_str_local_var_by_name(lexic, "priv");
- sz3 = get_var_size_by_name(lexic, "priv");
+ gcry_mpi_powm(e, g, priv, prime);
- if ( s1 == NULL || s2 == NULL || s3 == NULL )
- goto fail;
+ return e;
+}
- if ((dh = DH_new()) == NULL)
- goto fail;
-
- dh->p = BN_new();
- dh->g = BN_new();
- dh->priv_key = BN_new();
-
+/* compute the diffie hellman shared secret key. Neither GnuTLS nor
+ * libgcrypt contain a direct counterpart to OpenSSL's DH_compute_key,
+ * so we implement it ourselves. This function was copied from from
+ * gnutls and adapted to use gcrypt directly and to use a private key
+ * given as parameter to the function.
+ *
+ * The function returns the key on success and NULL on failure.
+ */
+static gcry_mpi_t
+calc_dh_key(gcry_mpi_t pub, gcry_mpi_t prime, gcry_mpi_t priv)
+{
+ gcry_mpi_t e;
- if (BN_bin2bn((const unsigned char*)s1, sz1, dh->p) == 0)
- goto fail;
- if (BN_bin2bn((const unsigned char*)s2, sz2, dh->g) == 0)
- goto fail;
- if (BN_bin2bn((const unsigned char*)s3, sz3, dh->priv_key) == 0)
- goto fail;
+ e = gcry_mpi_new(gcry_mpi_get_nbits(prime));
+ if (e == NULL)
+ {
+ return NULL;
+ }
- if (dh->p == NULL)
- goto fail;
+ gcry_mpi_powm(e, pub, priv, prime);
- if (DH_generate_key(dh) == 0)
- goto fail;
+ return e;
+}
- pubsize = BN_num_bytes(dh->pub_key);
- pub = emalloc(pubsize);
- if (pub == NULL)
- goto fail;
- BN_bn2bin(dh->pub_key, (unsigned char*)pub);
+/* nasl function
+ *
+ * dh_generate_key(p:mpi_p, g:mpi_g, priv:mpi_priv)
+ *
+ * Generates a Diffie-Hellman public key from the shared parameters p
+ * and g and the private parameter priv. The return value is the public
+ * key as an MPI.
+ */
+tree_cell *
+nasl_dh_generate_key(lex_ctxt* lexic)
+{
+ tree_cell *retc = NULL;
+ gcry_mpi_t p = NULL, g = NULL, priv = NULL, pub_mpi = NULL;
- if (pub[0] & 0x80)
- len = 1;
- else
- len = 0;
- retc->x.str_val = emalloc (pubsize+len);
- retc->x.str_val[0] = '\0';
- memcpy(retc->x.str_val+len, pub, pubsize);
- retc->size = pubsize + len;
+ retc = alloc_tree_cell(0, NULL);
+ retc->type = CONST_DATA;
- goto ret;
+ if (mpi_from_named_parameter(lexic, &p, "p", "nasl_dh_generate_key") < 0)
+ goto fail;
+ if (mpi_from_named_parameter(lexic, &g, "g", "nasl_dh_generate_key") < 0)
+ goto fail;
+ if (mpi_from_named_parameter(lexic, &priv, "priv", "nasl_dh_generate_key")
<0)
+ goto fail;
+ pub_mpi = calc_dh_public(g, p, priv);
+ if (pub_mpi == NULL)
+ goto fail;
+
+ if (set_mpi_retc(retc, pub_mpi) >= 0)
+ goto ret;
+
fail:
retc->x.str_val = emalloc(0);
retc->size = 0;
ret:
- DH_free(dh);
- free(pub);
+ gcry_mpi_release(p);
+ gcry_mpi_release(g);
+ gcry_mpi_release(priv);
+ gcry_mpi_release(pub_mpi);
return retc;
}
-
-tree_cell * nasl_dh_compute_key(lex_ctxt* lexic)
+/* nasl function
+ *
+ * DH_compute_key(p:mpi_p, g:mpi_g, dh_server_pub:mpi_server_pub,
+ * pub_key:mpi_client_pub, priv_key:mpi_client_priv)
+ *
+ * Computes the Diffie-Hellman shared secret key from the shared
+ * parameters p and g, the server's public key dh_server_pub and the
+ * client's public and private keys pub_key an priv_key. The return
+ * value is the shared secret key as an MPI.
+ */
+tree_cell *
+nasl_dh_compute_key(lex_ctxt* lexic)
{
- char *s1 = NULL,*s2 = NULL,*s3 = NULL,*s4 = NULL,*s5 = NULL;
- char *kbuf;
- tree_cell *retc = NULL;
- BIGNUM *dh_server_pub = NULL;
- DH *dh = NULL;
- int kout,klen,len;
- long sz1, sz2, sz3, sz4, sz5;
+ tree_cell *retc = NULL;
+ gcry_mpi_t p = NULL, g = NULL, dh_server_pub = NULL;
+ gcry_mpi_t pub_key = NULL, priv_key = NULL;
+ gcry_mpi_t shared = NULL;
retc = alloc_tree_cell(0, NULL);
retc->type = CONST_DATA;
-
- /* p bignum */
- s1 = get_str_local_var_by_name(lexic, "p");
- sz1 = get_var_size_by_name(lexic, "p");
-
- /* g bignum */
- s2 = get_str_local_var_by_name(lexic, "g");
- sz2 = get_var_size_by_name(lexic, "g");
- /* dh_server_pub bignum */
- s3 = get_str_local_var_by_name(lexic, "dh_server_pub");
- sz3 = get_var_size_by_name(lexic, "dh_server_pub");
+ if (mpi_from_named_parameter(lexic, &p, "p", "nasl_dh_compute_key") < 0)
+ goto fail;
+ if (mpi_from_named_parameter(lexic, &g, "g", "nasl_dh_compute_key") < 0)
+ goto fail;
+ if (mpi_from_named_parameter(lexic, &dh_server_pub, "dh_server_pub",
+ "nasl_dh_compute_key") < 0)
+ goto fail;
+ if (mpi_from_named_parameter(lexic, &pub_key, "pub_key",
+ "nasl_dh_compute_key") < 0)
+ goto fail;
+ if (mpi_from_named_parameter(lexic, &priv_key, "priv_key",
+ "nasl_dh_compute_key") < 0)
+ goto fail;
- /* public key bignum */
- s4 = get_str_local_var_by_name(lexic, "pub_key");
- sz4 = get_var_size_by_name(lexic, "pub_key");
+ shared = calc_dh_key(dh_server_pub, p, priv_key);
- /* private key bignum */
- s5 = get_str_local_var_by_name(lexic, "priv_key");
- sz5 = get_var_size_by_name(lexic, "priv_key");
+ if (set_mpi_retc(retc, shared) >= 0)
+ goto ret;
+fail:
+ retc->size = 0;
+ retc->x.str_val = emalloc(0);
+ret:
+ gcry_mpi_release(p);
+ gcry_mpi_release(g);
+ gcry_mpi_release(dh_server_pub);
+ gcry_mpi_release(priv_key);
+ gcry_mpi_release(pub_key);
+ gcry_mpi_release(shared);
+ return retc;
+}
- if ( s1 == NULL || s2 == NULL || s3 == NULL || s4 == NULL || s5 == NULL )
- goto fail;
+/*
+ * Extracts an MPI value from a libgcryt s-expression. The return value
+ * is the cadr of the subexpression whose car is given by token. The
+ * function returns NULL if the token doesn't occur in the expression or
+ * on other errors.
+ */
+static gcry_mpi_t
+extract_mpi_from_sexp(gcry_sexp_t sexp, const char * token)
+{
+ gcry_sexp_t child = NULL;
+ gcry_mpi_t mpi = NULL;
- if ((dh = DH_new()) == NULL)
- goto fail;
-
- dh->p = BN_new();
- dh->g = BN_new();
- dh->pub_key = BN_new();
- dh->priv_key = BN_new();
- dh_server_pub = BN_new();
+ child = gcry_sexp_find_token(sexp, token, strlen(token));
+ if (!child)
+ {
+ fprintf(stderr, "set_retc_from_sexp: no subexpression with token <%s>\n",
+ token);
+ }
+ else
+ {
+ mpi = gcry_sexp_nth_mpi(child, 1, GCRYMPI_FMT_USG);
+ }
- if (BN_bin2bn((const unsigned char*)s1, sz1, dh->p) == 0)
- goto fail;
- if (BN_bin2bn((const unsigned char*)s2, sz2, dh->g) == 0)
- goto fail;
- if (BN_bin2bn((const unsigned char*)s3, sz3, dh_server_pub) == 0)
- goto fail;
- if (BN_bin2bn((const unsigned char*)s4, sz4, dh->pub_key) == 0)
- goto fail;
- if (BN_bin2bn((const unsigned char*)s5, sz5, dh->priv_key) == 0)
- goto fail;
+ gcry_sexp_release(child);
- klen = DH_size(dh);
- kbuf = emalloc(klen);
- kout = DH_compute_key((unsigned char*)kbuf, dh_server_pub, dh);
+ return mpi;
+}
+
+/*
+ * Sets the return value in retc from an sexpression. The function uses
+ * extract_mpi_from_sexp to extract an MPI from the sexpression sexp and
+ * the subexpression given by token. The function return 1 on success
+ * and 0 on failure.
+ */
+static int
+set_retc_from_sexp(tree_cell *retc, gcry_sexp_t sexp, const char * token)
+{
+ int ret = 0;
+ gcry_mpi_t mpi = extract_mpi_from_sexp(sexp, token);
+ if (mpi)
+ {
+ ret = set_mpi_retc(retc, mpi);
+
+ gcry_mpi_release(mpi);
+ }
+
+ return ret;
+}
+
+/* nasl function
+ *
+ * rsa_public_decrypt(sig:signature, e:mpi_e, n:mpi_n)
+ *
+ * Decrypt the data in signature (usually an rsa-encrypted hash) with
+ * the public RSA key given by its parameters e and n. The return value
+ * is the decrypted data.
+ */
+tree_cell *
+nasl_rsa_public_decrypt(lex_ctxt* lexic)
+{
+ char *s1 = NULL;
+ tree_cell *retc = NULL;
+ long sz1;
+ gcry_mpi_t e = NULL, n = NULL;
+ gcry_sexp_t key = NULL, sig = NULL, decrypted = NULL;
+ gcry_error_t err;
+
+ retc = alloc_tree_cell(0, NULL);
+ retc->type = CONST_DATA;
+
+ /* encrypted data */
+ s1 = get_str_local_var_by_name(lexic, "sig");
+ sz1 = get_var_size_by_name(lexic, "sig");
+
+ if (mpi_from_named_parameter(lexic, &e, "e", "nasl_rsa_public_decrypt") < 0)
+ goto fail;
+ if (mpi_from_named_parameter(lexic, &n, "n", "nasl_rsa_public_decrypt") < 0)
+ goto fail;
+
+ err = gcry_sexp_build(&key, NULL, "(public-key (rsa (n %m) (e %m)))", n, e);
+ if (err)
+ {
+ print_gcrypt_error(lexic, "gcry_sexp_build pubkey", err);
+ goto fail;
+ }
+ err = gcry_sexp_build(&sig, NULL, "(data (value %b))", sz1, s1);
+ if (err)
+ {
+ print_gcrypt_error(lexic, "gcry_sexp_build sig", err);
+ goto fail;
+ }
- if (kbuf[0] & 0x80)
- len = 1;
- else
- len = 0;
- retc->x.str_val = emalloc (kout+len);
- retc->x.str_val[0] = '\0';
- memcpy(retc->x.str_val+len, kbuf, kout);
- retc->size = kout + len;
- goto ret;
+ /* gcry_pk_encrypt is equivalent to the public key decryption at least
+ * for RSA keys. */
+ err = gcry_pk_encrypt(&decrypted, sig, key);
+ if (err)
+ {
+ print_gcrypt_error(lexic, "gcry_pk_encrypt", err);
+ goto fail;
+ }
+ if (set_retc_from_sexp(retc, decrypted, "a") >= 0)
+ goto ret;
+
fail:
retc->size = 0;
retc->x.str_val = emalloc(0);
ret:
- DH_free(dh);
- BN_free(dh_server_pub);
+ gcry_sexp_release(decrypted);
+ gcry_sexp_release(key);
+ gcry_sexp_release(sig);
+ gcry_mpi_release(e);
+ gcry_mpi_release(n);
return retc;
}
+/* Creates a libgcryt s-expression from a GnuTLS private RSA key.
+ */
+#define NUM_RSA_PARAMS 6
+static gcry_sexp_t
+nasl_sexp_from_privkey(lex_ctxt* lexic, gnutls_x509_privkey_t privkey)
+{
+ gnutls_datum_t datums[NUM_RSA_PARAMS]; /* m/n, e, d, p, q, u */
+ gcry_mpi_t mpis[NUM_RSA_PARAMS]; /* m/n, e, d, p, q, u */
+ gcry_sexp_t key = NULL;
+ int err;
+ gcry_error_t gerr;
+ int i;
-tree_cell * nasl_rsa_public_decrypt(lex_ctxt* lexic)
+ for (i = 0; i < NUM_RSA_PARAMS; i++)
+ {
+ datums[i].data = NULL;
+ mpis[i] = NULL;
+ }
+
+ err = gnutls_x509_privkey_export_rsa_raw(privkey,
+ datums + 0, datums + 1,
+ datums + 2, datums + 3,
+ datums + 4, datums + 5);
+ if (err)
+ {
+ print_tls_error(lexic, "gnutls_x509_privkey_export_rsa_raw", err);
+ goto fail;
+ }
+
+ for (i = 0; i < NUM_RSA_PARAMS; i++)
+ {
+ err = mpi_from_string(lexic, mpis + i,
+ datums[i].data, datums[i].size,
+ "rsa parameter", "nasl_sexp_from_privkey");
+ if (err < 0)
+ goto fail;
+ }
+
+ /* make sure that p < q. libgcrypt requires this. */
+ if (gcry_mpi_cmp(mpis[3], mpis[4]) > 0)
+ {
+ gcry_mpi_swap(mpis[3], mpis[4]);
+ }
+
+ gerr = gcry_sexp_build(&key, NULL,
+ "(private-key (rsa (n %m) (e %m) (d %m)"
+ " (p %m) (q %m) (u %m)))",
+ mpis[0], mpis[1], mpis[2],
+ mpis[3], mpis[4], mpis[5]);
+ if (gerr)
+ {
+ print_gcrypt_error(lexic, "gcry_sexp_build", gerr);
+ goto fail;
+ }
+
+ fail:
+ for (i = 0; i < NUM_RSA_PARAMS; i++)
+ {
+ gnutls_free(datums[i].data);
+ gcry_mpi_release(mpis[i]);
+ }
+
+ return key;
+}
+
+
+/* nasl function
+ *
+ * rsa_sign(data:hash, priv:pem, passphrase:passphrase)
+ *
+ * Signs the data with the private RSA key priv given in PEM format.
+ * The passphrase is the passphrase needed to decrypt the private key.
+ * Returns the signed data.
+ *
+ * In the OpenSSL based nasl, the key was not given in PEM form and with
+ * a passphrase. Instead it was given as the RSA parameters e, n and d.
+ * libgcrypt always requires all the parameters (including p, g, and u),
+ * so this function was changed to simply accept the full private key in
+ * PEM form. The one place where it was called had that the key
+ * available in that form.
+ */
+tree_cell *
+nasl_rsa_sign(lex_ctxt* lexic)
{
- char *s1 = NULL,*s2 = NULL,*s3 = NULL, *decrypted = NULL;
- tree_cell *retc = NULL;
- RSA *rsa = NULL;
- int len;
- long sz1, sz2, sz3;
+ tree_cell *retc = NULL;
+ char * data;
+ int data_size;
+ gcry_sexp_t ssig = NULL, sdata = NULL, skey = NULL;
+ gnutls_x509_privkey_t priv_key = NULL;
+ gcry_error_t err;
+ if (check_authenticated(lexic) < 0)
+ return FAKE_CELL;
+
retc = alloc_tree_cell(0, NULL);
retc->type = CONST_DATA;
-
- /* sig bignum */
- s1 = get_str_local_var_by_name(lexic, "sig");
- sz1 = get_var_size_by_name(lexic, "sig");
-
- /* e bignum */
- s2 = get_str_local_var_by_name(lexic, "e");
- sz2 = get_var_size_by_name(lexic, "e");
- /* n bignum */
- s3 = get_str_local_var_by_name(lexic, "n");
- sz3 = get_var_size_by_name(lexic, "n");
-
- if ( s1 == NULL || s2 == NULL || s3 == NULL )
+ data = get_str_local_var_by_name(lexic, "data");
+ data_size = get_var_size_by_name(lexic, "data");
+ if (!data)
goto fail;
- if ((rsa = RSA_new()) == NULL)
+ priv_key = nasl_load_privkey_param(lexic, "priv", "passphrase");
+ if (!priv_key)
goto fail;
-
- rsa->e = BN_new();
- rsa->n = BN_new();
+ err = gcry_sexp_build(&sdata, NULL, "(data (flags pkcs1) (hash sha1 %b))",
+ data_size, data);
+ if (err)
+ {
+ print_gcrypt_error(lexic, "gcry_sexp_build for data", err);
+ goto fail;
+ }
- if (BN_bin2bn((const unsigned char*)s3, sz3, rsa->n) == 0)
+ skey = nasl_sexp_from_privkey(lexic, priv_key);
+ if (!skey)
goto fail;
- if (BN_bin2bn((const unsigned char*)s2, sz2, rsa->e) == 0)
- goto fail;
- decrypted = emalloc(sz1);
- if (!decrypted)
- goto fail;
- if ((len = RSA_public_decrypt(sz1, (unsigned char*)s1, (unsigned
char*)decrypted, rsa,
- RSA_PKCS1_PADDING)) < 0)
- goto fail;
+ err = gcry_pk_sign(&ssig, sdata, skey);
+ if (err)
+ {
+ print_gcrypt_error(lexic, "gcry_pk_sign", err);
+ goto fail;
+ }
- retc->size = len;
- retc->x.str_val = decrypted;
- goto ret;
+ if (set_retc_from_sexp(retc, ssig, "s") >= 0)
+ goto ret;
fail:
retc->size = 0;
retc->x.str_val = emalloc(0);
ret:
- RSA_free(rsa);
+ gcry_sexp_release(ssig);
+ gcry_sexp_release(sdata);
+ gcry_sexp_release(skey);
+ gnutls_x509_privkey_deinit(priv_key);
return retc;
}
-tree_cell * nasl_rsa_sign(lex_ctxt* lexic)
+/* nasl function
+ *
+ * dsa_do_verify(p:mpi_p, g:mpi_g, q:mpi_q, pub:mpi_pub,
+ * r:mpi_r, s:mpi_s, data:hash)
+ *
+ * Verify that the DSA signature given by r and s matches the hash given
+ * in data using the public DSA key given by p, g, q and pub. Returns 1
+ * if the signature is valid and 0 if it's invalid.
+ */
+tree_cell *
+nasl_dsa_do_verify(lex_ctxt* lexic)
{
- char *s1 = NULL,*s2 = NULL,*s3 = NULL, *s4 = NULL, *sig = NULL, *signature =
NULL;
tree_cell *retc = NULL;
- RSA *rsa = NULL;
- int ok;
- long sz1, sz2, sz3, sz4, slen;
- unsigned int len;
+ gcry_mpi_t p = NULL, g = NULL, q = NULL, pub = NULL, data = NULL;
+ gcry_mpi_t r = NULL, s = NULL;
+ gcry_sexp_t ssig = NULL, skey = NULL, sdata = NULL;
+ gcry_error_t err;
- if ( check_authenticated(lexic) < 0 ) return FAKE_CELL;
+ retc = emalloc(sizeof(tree_cell));
+ retc->ref_count = 1;
+ retc->type = CONST_INT;
+ retc->x.i_val = 0;
- retc = alloc_tree_cell(0, NULL);
- retc->type = CONST_DATA;
-
- /* sig bignum */
- s1 = get_str_local_var_by_name(lexic, "data");
- sz1 = get_var_size_by_name(lexic, "data");
-
- /* e bignum */
- s2 = get_str_local_var_by_name(lexic, "e");
- sz2 = get_var_size_by_name(lexic, "e");
+ if (mpi_from_named_parameter(lexic, &p, "p", "nasl_dsa_do_sign") < 0)
+ goto fail;
+ if (mpi_from_named_parameter(lexic, &g, "g", "nasl_dsa_do_sign") < 0)
+ goto fail;
+ if (mpi_from_named_parameter(lexic, &q, "q", "nasl_dsa_do_sign") < 0)
+ goto fail;
+ if (mpi_from_named_parameter(lexic, &pub, "pub", "nasl_dsa_do_sign") < 0)
+ goto fail;
+ if (mpi_from_named_parameter(lexic, &r, "r", "nasl_dsa_do_sign") < 0)
+ goto fail;
+ if (mpi_from_named_parameter(lexic, &s, "s", "nasl_dsa_do_sign") < 0)
+ goto fail;
+ if (mpi_from_named_parameter(lexic, &data, "data", "nasl_dsa_do_sign") < 0)
+ goto fail;
- /* n bignum */
- s3 = get_str_local_var_by_name(lexic, "n");
- sz3 = get_var_size_by_name(lexic, "n");
+ err = gcry_sexp_build(&sdata, NULL, "(data (flags raw) (value %m))", data);
+ if (err)
+ {
+ print_gcrypt_error(lexic, "gcry_sexp_build for data", err);
+ goto fail;
+ }
- /* d bignum */
- s4 = get_str_local_var_by_name(lexic, "d");
- sz4 = get_var_size_by_name(lexic, "d");
+ err = gcry_sexp_build(&skey, NULL,
+ "(public-key (dsa (p %m) (q %m) (g %m) (y %m)))",
+ p, q, g, pub);
+ if (err)
+ {
+ print_gcrypt_error(lexic, "gcry_sexp_build for private key", err);
+ goto fail;
+ }
- if ( s1 == NULL || s2 == NULL || s3 == NULL || s4 == NULL )
- goto fail;
+ err = gcry_sexp_build(&ssig, NULL, "(sig-val (dsa (r %m) (s %m)))", r, s);
+ if (err)
+ {
+ print_gcrypt_error(lexic, "gcry_sexp_build for signature", err);
+ goto fail;
+ }
- if ((rsa = RSA_new()) == NULL)
- goto fail;
-
- rsa->e = BN_new();
- rsa->n = BN_new();
- rsa->d = BN_new();
+ err = gcry_pk_verify(ssig, sdata, skey);
+ if (err == 0)
+ retc->x.i_val = 1;
+ else if (gcry_err_code(err) == GPG_ERR_BAD_SIGNATURE)
+ retc->x.i_val = 0;
+ else
+ {
+ print_gcrypt_error(lexic, "gcry_pk_sign", err);
+ goto fail;
+ }
- if (BN_bin2bn((const unsigned char*)s3, sz3, rsa->n) == 0)
+fail:
+ gcry_mpi_release(p);
+ gcry_mpi_release(g);
+ gcry_mpi_release(q);
+ gcry_mpi_release(pub);
+ gcry_mpi_release(r);
+ gcry_mpi_release(s);
+ gcry_mpi_release(data);
+ gcry_sexp_release(ssig);
+ gcry_sexp_release(skey);
+ gcry_sexp_release(sdata);
+
+ return retc;
+}
+
+/* nasl function
+ *
+ * dsa_do_sign(p:mpi_p, g:mpi_g, q:mpi_q, pub:mpi_pub, priv:mpi_priv,
+ * data:hash)
+ *
+ * Computes the DSA signature of the hash in data using the private DSA
+ * key given by p, g, q, pub and priv. The return value is a 40 byte
+ * string encoding the two MPIs r and s of the DSA signature. The first
+ * 20 bytes are the value of r and the last 20 bytes are the value of s.
+ */
+tree_cell *
+nasl_dsa_do_sign(lex_ctxt* lexic)
+{
+ tree_cell *retc = NULL;
+ gcry_mpi_t p = NULL, g = NULL, q = NULL, pub = NULL, priv = NULL, data =
NULL;
+ gcry_mpi_t r = NULL, s = NULL;
+ gcry_sexp_t ssig = NULL, skey = NULL, sdata = NULL;
+ long rlen, slen;
+ unsigned char * sigblob = NULL;
+ gcry_error_t err;
+
+ if (check_authenticated(lexic) < 0)
+ return FAKE_CELL;
+
+ retc = emalloc(sizeof(tree_cell));
+ retc->ref_count = 1;
+ retc->type = CONST_DATA;
+ retc->x.i_val = 0;
+
+ if (mpi_from_named_parameter(lexic, &p, "p", "nasl_dsa_do_sign") < 0)
goto fail;
- if (BN_bin2bn((const unsigned char*)s2, sz2, rsa->e) == 0)
+ if (mpi_from_named_parameter(lexic, &g, "g", "nasl_dsa_do_sign") < 0)
goto fail;
- if (BN_bin2bn((const unsigned char*)s4, sz4, rsa->d) == 0)
+ if (mpi_from_named_parameter(lexic, &q, "q", "nasl_dsa_do_sign") < 0)
goto fail;
-
- slen = RSA_size(rsa);
- sig = emalloc(slen);
- if (!sig)
+ if (mpi_from_named_parameter(lexic, &pub, "pub", "nasl_dsa_do_sign") < 0)
goto fail;
-
- ok = RSA_sign(NID_sha1, (unsigned char*)s1, sz1, (unsigned char*)sig, &len,
rsa);
- if (!ok || len > slen)
+ if (mpi_from_named_parameter(lexic, &priv, "priv", "nasl_dsa_do_sign") < 0)
goto fail;
-
- signature = emalloc(len);
- if (!signature)
+ if (mpi_from_named_parameter(lexic, &data, "data", "nasl_dsa_do_sign") < 0)
goto fail;
-
- memcpy(signature,sig,len);
- retc->size = len;
- retc->x.str_val = signature;
- goto ret;
+ err = gcry_sexp_build(&sdata, NULL, "(data (flags raw) (value %m))", data);
+ if (err)
+ {
+ print_gcrypt_error(lexic, "gcry_sexp_build for data", err);
+ goto fail;
+ }
+
+ err = gcry_sexp_build(&skey, NULL,
+ "(private-key (dsa (p %m) (q %m) (g %m) (y %m) (x %m)))",
+ p, q, g, pub, priv);
+ if (err)
+ {
+ print_gcrypt_error(lexic, "gcry_sexp_build for private-key", err);
+ goto fail;
+ }
+
+ err = gcry_pk_sign(&ssig, sdata, skey);
+ if (err)
+ {
+ print_gcrypt_error(lexic, "gcry_pk_sign", err);
+ goto fail;
+ }
+
+ r = extract_mpi_from_sexp(ssig, "r");
+ s = extract_mpi_from_sexp(ssig, "s");
+ if (!r || !s)
+ goto fail;
+
+ rlen = (gcry_mpi_get_nbits(r) + 7) / 8;
+ slen = (gcry_mpi_get_nbits(s) + 7) / 8;
+ if (rlen > INTBLOB_LEN || slen > INTBLOB_LEN)
+ {
+ nasl_perror(lexic, "rlen (%d) or slen (%d) > INTBLOB_LEN (%d)\n",
+ rlen, slen, INTBLOB_LEN);
+ goto fail;
+ }
+
+ sigblob = emalloc(SIGBLOB_LEN);
+ memset(sigblob, 0, SIGBLOB_LEN);
+
+ err = gcry_mpi_print(GCRYMPI_FMT_USG,
+ (unsigned char*)(sigblob + SIGBLOB_LEN - INTBLOB_LEN -
rlen),
+ rlen, NULL, r);
+ if (err)
+ {
+ print_gcrypt_error(lexic, "gcry_mpi_print(r)", err);
+ goto fail;
+ }
+ err = gcry_mpi_print(GCRYMPI_FMT_USG,
+ (unsigned char*)(sigblob+ SIGBLOB_LEN - slen),
+ rlen, NULL, s);
+ if (err)
+ {
+ print_gcrypt_error(lexic, "gcry_mpi_print(s)", err);
+ goto fail;
+ }
+
+ retc->x.str_val = (char*)sigblob;
+ sigblob = NULL;
+ retc->size = SIGBLOB_LEN;
+
fail:
- retc->size = 0;
- retc->x.str_val = emalloc(0);
-ret:
- RSA_free(rsa);
- free(sig);
+ gcry_mpi_release(p);
+ gcry_mpi_release(g);
+ gcry_mpi_release(q);
+ gcry_mpi_release(pub);
+ gcry_mpi_release(priv);
+ gcry_mpi_release(data);
+ gcry_mpi_release(r);
+ gcry_mpi_release(s);
+ gcry_sexp_release(ssig);
+ gcry_sexp_release(skey);
+ gcry_sexp_release(sdata);
+ efree(&sigblob);
+
return retc;
}
-
-tree_cell * nasl_bf_cbc(lex_ctxt* lexic, int enc)
+/* Implements the nasl functions bf_cbc_encrypt and bf_cbc_decrypt. */
+tree_cell *
+nasl_bf_cbc(lex_ctxt* lexic, int enc)
{
- char *enckey = NULL,*iv = NULL,*data = NULL,*out = NULL;
- tree_cell *retc = NULL;
+ tree_cell *retc = NULL;
+ char *enckey = NULL, *iv = NULL, *data = NULL, *out = NULL;
long enckeylen, ivlen, datalen;
- BF_KEY key;
+ gcry_cipher_hd_t hd = NULL;
anon_nasl_var v;
nasl_array *a;
+ gcry_error_t err;
retc = alloc_tree_cell(0, NULL);
retc->type = CONST_DATA;
-
- /* sig bignum */
+
+ /* key */
enckey = get_str_local_var_by_name(lexic, "key");
enckeylen = get_var_size_by_name(lexic, "key");
+ /* initialization vector */
iv = get_str_local_var_by_name(lexic, "iv");
ivlen = get_var_size_by_name(lexic, "iv");
+ /* data to decrypt/encrypt*/
data = get_str_local_var_by_name(lexic, "data");
datalen = get_var_size_by_name(lexic, "data");
if ( enckey == NULL || data == NULL || iv == NULL )
goto fail;
+ if (enckeylen != 16)
+ {
+ /* key length must be 16 for compatibility with libnasl code from
+ * before the OpenSSL -> GnuTLS migration */
+ nasl_perror(lexic, "nasl_bf_cbc: unexpected enckeylen = %d; must be
16\n",
+ enckeylen);
+ goto fail;
+ }
+ if (ivlen < 8)
+ {
+ nasl_perror(lexic, "nasl_bf_cbc: unexpected ivlen = %d; must >= 8\n",
+ ivlen);
+ goto fail;
+ }
+ if (datalen < 8)
+ {
+ nasl_perror(lexic, "nasl_bf_cbc: unexpected datalen = %d; must >= 8\n",
+ datalen);
+ goto fail;
+ }
- /* key len = 16 : { "blowfish-cbc", SSH_CIPHER_SSH2, 8, 16, EVP_bf_cbc }*/
- BF_set_key(&key, 16, (unsigned char*)enckey);
+ err = gcry_cipher_open(&hd, GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_CBC, 0);
+ if (err)
+ {
+ print_gcrypt_error(lexic, "gcry_cipher_open", err);
+ goto fail;
+ }
+ err = gcry_cipher_setkey(hd, enckey, enckeylen);
+ if (err)
+ {
+ print_gcrypt_error(lexic, "gcry_cipher_setkey", err);
+ goto fail;
+ }
+ err = gcry_cipher_setiv(hd, iv, ivlen);
+ if (err)
+ {
+ print_gcrypt_error(lexic, "gcry_cipher_setiv", err);
+ goto fail;
+ }
+
out = emalloc(datalen);
if (!out)
goto fail;
- BF_cbc_encrypt((unsigned char*)data, (unsigned char*)out, datalen, &key,
(unsigned char*)iv, enc);
+ if (enc)
+ err = gcry_cipher_encrypt(hd, out, datalen, data, datalen);
+ else
+ err = gcry_cipher_decrypt(hd, out, datalen, data, datalen);
+ if (err)
+ {
+ print_gcrypt_error(lexic, "gcry_cipher_encrypt", err);
+ goto fail;
+ }
retc->type = DYN_ARRAY;
retc->x.ref_val = a = emalloc(sizeof(nasl_array));
@@ -562,395 +1100,308 @@
v.v.v_str.s_siz = datalen;
v.v.v_str.s_val = (unsigned char*)out;
(void) add_var_to_list(a, 0, &v);
- free(out);
/* second iv */
+ /* the iv to use to for the next part of the data is always the last
+ * eight bytes of the cipher text. When encrypting the cipher text is
+ * in out when decrypting it's in data.
+ */
v.var_type = VAR2_DATA;
- v.v.v_str.s_siz = ivlen;
- v.v.v_str.s_val = (unsigned char*)iv;
+ v.v.v_str.s_siz = 8;
+ v.v.v_str.s_val = (unsigned char*)((enc ? out : data) + datalen - 8);
(void) add_var_to_list(a, 1, &v);
goto ret;
-fail:
+ fail:
retc->type = CONST_DATA;
retc->x.str_val = emalloc(0);
retc->size = 0;
-ret:
+
+ ret:
+ efree(&out);
+ gcry_cipher_close(hd);
+
return retc;
}
-tree_cell * nasl_dsa_do_verify(lex_ctxt* lexic)
+/* nasl function
+ *
+ * bf_cbc_encrypt(key:key, iv:iv, data:data)
+ *
+ * Encrypt the plain text data using the blowfish algorithm in CBC mode
+ * with the key key and the initialization vector iv. The key must be
+ * 16 bytes long. The iv must be at least 8 bytes long. data must be a
+ * multiple of 8 bytes long.
+ *
+ * The return value is an array a with a[0] being the encrypted data and
+ * a[1] the new initialization vector to use for the next part of the
+ * data.
+ */
+tree_cell *
+nasl_bf_cbc_encrypt(lex_ctxt* lexic)
{
- char *p = NULL,*g = NULL,*q = NULL, *pub = NULL,*r = NULL,*s = NULL;
- char * data = NULL;
- tree_cell *retc = NULL;
- DSA *dsa = NULL;
- DSA_SIG * sig = NULL;
- long plen, glen, qlen, publen, rlen, slen, datalen;
-
- retc = emalloc(sizeof(tree_cell));
- retc->ref_count = 1;
- retc->type = CONST_INT;
- retc->x.i_val = 0;
-
- /* p bignum */
- p = get_str_local_var_by_name(lexic, "p");
- plen = get_var_size_by_name(lexic, "p");
-
- /* g bignum */
- g = get_str_local_var_by_name(lexic, "g");
- glen = get_var_size_by_name(lexic, "g");
-
- /* q bignum */
- q = get_str_local_var_by_name(lexic, "q");
- qlen = get_var_size_by_name(lexic, "q");
-
- /* pub bignum */
- pub = get_str_local_var_by_name(lexic, "pub");
- publen = get_var_size_by_name(lexic, "pub");
-
- /* r bignum */
- r = get_str_local_var_by_name(lexic, "r");
- rlen = get_var_size_by_name(lexic, "r");
-
- /* s bignum */
- s = get_str_local_var_by_name(lexic, "s");
- slen = get_var_size_by_name(lexic, "s");
-
- /* data */
- data = get_str_local_var_by_name(lexic, "data");
- datalen = get_var_size_by_name(lexic, "data");
- if ( p == NULL || g == NULL || q == NULL || pub == NULL || r == NULL || s
== NULL )
- goto fail;
-
- if ((dsa = DSA_new()) == NULL)
- goto fail;
-
- if ((sig = DSA_SIG_new()) == NULL)
- goto fail;
-
- if (BN_bin2bn((const unsigned char*)p, plen, dsa->p) == 0)
- goto fail;
- if (BN_bin2bn((const unsigned char*)g, glen, dsa->g) == 0)
- goto fail;
- if (BN_bin2bn((const unsigned char*)q, qlen, dsa->q) == 0)
- goto fail;
- if (BN_bin2bn((const unsigned char*)pub, publen, dsa->pub_key) == 0)
- goto fail;
- if (BN_bin2bn((const unsigned char*)r, rlen, sig->r) == 0)
- goto fail;
- if (BN_bin2bn((const unsigned char*)s, slen, sig->s) == 0)
- goto fail;
-
- if (DSA_do_verify((unsigned char*)data, datalen, sig, dsa))
- retc->x.i_val = 1;
-
-fail:
- DSA_free(dsa);
- DSA_SIG_free(sig);
- return retc;
+ return nasl_bf_cbc(lexic, 1);
}
-tree_cell * nasl_dsa_do_sign(lex_ctxt* lexic)
+/* nasl function
+ *
+ * bf_cbc_decrypt(key:key, iv:iv, data:data)
+ *
+ * Decrypt the cipher text data using the blowfish algorithm in CBC mode
+ * with the key key and the initialization vector iv. The key must be
+ * 16 bytes long. The iv must be at least 8 bytes long. data must be a
+ * multiple of 8 bytes long.
+ *
+ * The return value is an array a with a[0] being the plain text data
+ * and a[1] the new initialization vector to use for the next part of
+ * the data.
+ */
+tree_cell *
+nasl_bf_cbc_decrypt(lex_ctxt* lexic)
{
- char *p = NULL,*g = NULL,*q = NULL, *pub = NULL,*priv = NULL;
- char * data = NULL;
- tree_cell *retc = NULL;
- DSA *dsa = NULL;
- DSA_SIG * sig = NULL;
- char *sigblob;
- long plen, glen, qlen, publen, privlen, rlen, slen, datalen;
+ return nasl_bf_cbc(lexic, 0);
+}
- if ( check_authenticated(lexic) < 0 ) return FAKE_CELL;
+/*--------------------------------------------------------------*/
- retc = emalloc(sizeof(tree_cell));
- retc->ref_count = 1;
- retc->type = CONST_DATA;
- retc->x.i_val = 0;
-
- /* p bignum */
- p = get_str_local_var_by_name(lexic, "p");
- plen = get_var_size_by_name(lexic, "p");
-
- /* g bignum */
- g = get_str_local_var_by_name(lexic, "g");
- glen = get_var_size_by_name(lexic, "g");
+/* Reads the contents of the file given by filename into memory and
+ * returns it as a gnutls_datum_t. If an error occurs the
+ * gnutls_datum_t's data field is NULL.
+ */
+gnutls_datum_t
+map_file(const char * filename)
+{
+ struct stat st;
+ int fd = -1;
+ char * map;
+ gnutls_datum_t contents = {NULL, 0};
- /* q bignum */
- q = get_str_local_var_by_name(lexic, "q");
- qlen = get_var_size_by_name(lexic, "q");
-
- /* pub bignum */
- pub = get_str_local_var_by_name(lexic, "pub");
- publen = get_var_size_by_name(lexic, "pub");
-
- /* r bignum */
- priv = get_str_local_var_by_name(lexic, "priv");
- privlen = get_var_size_by_name(lexic, "priv");
-
- /* data */
- data = get_str_local_var_by_name(lexic, "data");
- datalen = get_var_size_by_name(lexic, "data");
-
- if ( p == NULL || g == NULL || q == NULL || pub == NULL || priv == NULL ||
data == NULL )
- goto fail;
-
- if ((dsa = DSA_new()) == NULL)
+ fd = open(filename, O_RDONLY);
+ if (fd < 0)
goto fail;
-
- if ((sig = DSA_SIG_new()) == NULL)
+ if (fstat(fd, &st) < 0)
goto fail;
- dsa->p = BN_new();
- dsa->g = BN_new();
- dsa->q = BN_new();
- dsa->pub_key = BN_new();
- dsa->priv_key = BN_new();
-
- if (BN_bin2bn((const unsigned char*)p, plen, dsa->p) == 0)
- goto fail;
- if (BN_bin2bn((const unsigned char*)g, glen, dsa->g) == 0)
- goto fail;
- if (BN_bin2bn((const unsigned char*)q, qlen, dsa->q) == 0)
- goto fail;
- if (BN_bin2bn((const unsigned char*)pub, publen, dsa->pub_key) == 0)
- goto fail;
- if (BN_bin2bn((const unsigned char*)priv, privlen, dsa->priv_key) == 0)
- goto fail;
+ map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (map == NULL || map == MAP_FAILED)
+ goto fail;
- sig = DSA_do_sign((unsigned char*)data, datalen, dsa);
- if (!sig)
- goto fail;
+ contents.data = (unsigned char*)nasl_strndup(map, st.st_size);
+ contents.size = st.st_size;
+ munmap(map, st.st_size);
- sigblob = emalloc(SIGBLOB_LEN);
- memset(sigblob, 0, SIGBLOB_LEN);
- rlen = BN_num_bytes(sig->r);
- slen = BN_num_bytes(sig->s);
-
- if (rlen > INTBLOB_LEN || slen > INTBLOB_LEN)
- goto fail;
-
- BN_bn2bin(sig->r, (unsigned char*)(sigblob+ SIGBLOB_LEN - INTBLOB_LEN -
rlen));
- BN_bn2bin(sig->s, (unsigned char*)(sigblob+ SIGBLOB_LEN - slen));
-
- retc->x.str_val = sigblob;
- retc->size = SIGBLOB_LEN;
-
-fail:
- DSA_free(dsa);
- DSA_SIG_free(sig);
- return retc;
+ fail:
+ if (fd >= 0)
+ close(fd);
+ return contents;
}
-tree_cell * nasl_bf_cbc_encrypt(lex_ctxt* lexic)
-{
- return nasl_bf_cbc(lexic, BF_ENCRYPT);
-}
+/*----------------------------- Script signature management
------------------------------------------*/
-
-tree_cell * nasl_bf_cbc_decrypt(lex_ctxt* lexic)
+/*
+ * Signs a given script
+ */
+int
+generate_signed_script(char * filename)
{
- return nasl_bf_cbc(lexic, BF_DECRYPT);
-}
+ const char * pemfilename = NESSUS_STATE_DIR "/openvas/openvas_org.priv.pem";
+ 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;
+ err = gnutls_x509_privkey_init(&privkey);
+ if (err)
+ {
+ print_tls_error(NULL, "gnutls_x509_privkey_init", err);
+ goto fail;
+ }
-/*--------------------------------------------------------------*/
+ pem = map_file(pemfilename);
+ if (!pem.data)
+ goto fail;
-char * map_file(char * filename, int * len)
-{
- struct stat st;
- int fd;
- char * map, * ret;
+ err = gnutls_x509_privkey_import(privkey, &pem, GNUTLS_X509_FMT_PEM);
+ if (err)
+ {
+ print_tls_error(NULL, "gnutls_x509_privkey_import", err);
+ goto fail;
+ }
- fd = open(filename, O_RDONLY);
- if ( fd < 0 ) return NULL;
- if ( fstat(fd, &st) < 0 )
- {
- close(fd);
- return NULL;
- }
+ script = map_file(filename);
+ if (!script.data)
+ {
+ goto fail;
+ }
- map = mmap ( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
- if ( map == NULL || map == MAP_FAILED )
- {
- close(fd);
- return NULL;
- }
+ /* 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(NULL, "gnutls_x509_privkey_sign_data", err);
+ goto fail;
+ }
- ret = nasl_strndup(map, st.st_size);
- munmap(map, st.st_size);
- close(fd);
- *len = st.st_size;
- return ret;
-}
+ signature = emalloc(signature_size);
+ err = gnutls_x509_privkey_sign_data(privkey, GNUTLS_DIG_SHA1, 0, &script,
+ signature, &signature_size);
+ if (err)
+ {
+ print_tls_error(NULL, "gnutls_x509_privkey_sign_data", err);
+ goto fail;
+ }
+ /* print the header with the signature */
+ printf("#TRUSTED ");
+ for (i = 0; i < signature_size; i++)
+ {
+ printf("%.2x", signature[i]);
+ }
+ printf("\n");
-/*----------------------------- Script signature management
------------------------------------------*/
+ /* strip the size from the end of the script again */
+ script.size -= sizeof(be_len);
+ memset(script.data + script.size, 0, sizeof(be_len));
-/*
- * Signs a given script
- */
-int generate_signed_script(char * filename)
-{
- RSA * rsa = NULL;
- FILE * fp = fopen(NESSUS_STATE_DIR "/nessus/nessus_org.priv.pem", "r");
- unsigned char * result;
- unsigned int len;
- int i;
- char md[SHA_DIGEST_LENGTH+1];
- int be_len;
+ /* print the script itself */
+ printf("%s", script.data);
+ fflush(stdout);
- char * msg;
- int msg_len;
+ result = 0;
+ fail:
+ efree(&pem.data);
+ efree(&script.data);
+ efree(&signature);
+ gnutls_x509_privkey_deinit(privkey);
- msg = map_file(filename, &msg_len);
- if ( msg == NULL ) {
- perror("mmap ");
- exit(0);
- }
+ return result;
+}
- /* Append the size of the file at the end of the message */
- msg = erealloc(msg, msg_len + sizeof(msg_len));
- be_len = htonl(msg_len);
- memcpy(msg + msg_len, &be_len, sizeof(msg_len));
+/* Decodes a sequence of hexadecimal numbers. */
+static ptrdiff_t
+hexdecode(unsigned char *to, const unsigned char * from)
+{
+ char temp[3] = {0, 0, 0};
+ unsigned char * start = to;
+ while (from[0] && from[1])
+ {
+ temp[0] = from[0];
+ temp[1] = from[1];
+ *to = strtoul(temp, NULL, 16);
+ to += 1;
+ from += 2;
+ }
-
- SHA1((unsigned char*)msg, msg_len + sizeof(msg_len), (unsigned char*)md);
- 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;
- }
-
- len = RSA_size(rsa);
- result = emalloc(len);
-
- RSA_sign(NID_sha1, (unsigned char*)md, SHA_DIGEST_LENGTH, (unsigned
char*)result, &len, rsa);
- printf("#TRUSTED ");
- for ( i = 0 ; i < len ; i ++ )
- {
- printf("%.2x", result[i]);
- }
- printf("\n", len);
- memset(msg + msg_len, 0, sizeof(msg_len));
- printf("%s", msg);
- fflush(stdout);
- efree(&msg);
- efree(&result);
- RSA_free(rsa);
-
- return 0;
+ return to - start;
}
-
-/*
+/*
* Verify a script signature
*
+ * In the original OpenSSL based code the public key was stored in a
+ * format that GnuTLS cannot read. The new code requires a real x509
+ * certificate.
+ *
* Returns :
* -1 : if an error occured
* 0 : if the signature matches
* 1 : if the signature does NOT match
*/
-int verify_script_signature(char * filename)
+int
+verify_script_signature(char * filename)
{
- char * msg;
- int msg_len;
- char * t;
- unsigned char md[SHA_DIGEST_LENGTH+1];
- RSA * rsa = NULL;
- FILE * fp = fopen(NESSUS_STATE_DIR "/nessus/nessus_org.pem", "r");
- char sig[16384];
- unsigned char bin_sig[8192];
- int binsz = 0;
- int i;
- int sig_len = 0;
- int res = -1;
- int be_len;
+ const char * pemfilename = NESSUS_STATE_DIR "/openvas/openvas_org.pem";
+ char * t;
+ int be_len;
+ gnutls_x509_crt_t cert = NULL;
+ gnutls_datum_t pem = {NULL, 0};
+ gnutls_datum_t script = {NULL, 0};
+ gnutls_datum_t data_to_hash;
+ gnutls_datum_t signature;
+ int result = -1;
+ int err;
+ pem = map_file(pemfilename);
+ if (!pem.data)
+ goto fail;
- if ( fp == NULL )
- {
- fprintf(stderr, "Open %s/nessus/nessus_org.pem : %s\n", NESSUS_STATE_DIR,
strerror(errno));
- return -1;
- }
+ err = gnutls_x509_crt_init(&cert);
+ if (err)
+ {
+ print_tls_error(NULL, "gnutls_x509_crt_init", err);
+ goto fail;
+ }
+ err = gnutls_x509_crt_import(cert, &pem, GNUTLS_X509_FMT_PEM);
+ if (err)
+ {
+ print_tls_error(NULL, "gnutls_x509_crt_import", err);
+ goto fail;
+ }
- rsa = PEM_read_RSA_PUBKEY(fp, NULL, NULL, NULL);
- fclose(fp);
- if ( rsa == NULL ) return -1;
+ script = map_file(filename);
+ if (!script.data)
+ {
+ goto fail;
+ }
- msg = map_file(filename, &msg_len);
- if ( msg == NULL ) return -1;
+ /* Make room for the size of the file at the end of the script */
+ script.data = erealloc(script.data, script.size + sizeof(be_len));
- msg = erealloc(msg, msg_len + sizeof(msg_len));
-
- t = strchr(msg, '\n');
- if ( t == NULL ) goto err;
- t[0] = '\0'; t ++;
- strncpy(sig, msg + strlen("#TRUSTED "), sizeof(sig) - 1 );
- sig[sizeof(sig) - 1] = '\0';
+ /* split the script into the signature (first line) and the rest */
+ t = strchr((char*)script.data, '\n');
+ if (t == NULL)
+ goto fail;
+ t[0] = '\0'; t++;
- /* Append the size of the message at the end of it */
- msg_len = msg_len - ( (int)t - (int)msg);
- be_len = htonl(msg_len);
- memcpy(t + msg_len, &be_len, sizeof(msg_len));
+ /* The data to hash is the rest with the size of the rest appended */
+ data_to_hash.data = (unsigned char*)t;
+ data_to_hash.size = script.size - (data_to_hash.data - script.data);
+ be_len = htonl(data_to_hash.size);
+ memcpy(data_to_hash.data + data_to_hash.size, &be_len, sizeof(be_len));
+ data_to_hash.size += sizeof(be_len);
- SHA1((unsigned char*)t, msg_len + sizeof(msg_len), md);
+ /* decode the hex signature. We can do it in place because the binary
+ * signature is always shorter than it's hexadecimal
+ * representation. Also, the caller has already checked that the
+ * script starts with "#TRUSTED", so we can simply skip it here */
+ signature.data = script.data;
+ signature.size = hexdecode(signature.data, script.data + strlen("#TRUSTED
"));
- sig_len = strlen(sig);
+ err = gnutls_x509_crt_verify_data(cert, 0, &data_to_hash, &signature);
+ if (err < 0)
+ {
+ print_tls_error(NULL, "gnutls_x509_crt_verify_data", err);
+ goto fail;
+ }
- 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 */
- }
-
-
+ result = err == 1 ? 0 : 1;
- res = RSA_verify(NID_sha1, md, SHA_DIGEST_LENGTH, bin_sig, binsz, rsa);
- RSA_free(rsa);
- efree(&msg);
- return res == 1 ? 0 : 1;
-
-err:
- RSA_free(rsa);
- efree(&msg);
- return -1;
-
-}
+ fail:
+ gnutls_x509_crt_deinit(cert);
+ efree(&script.data);
+ efree(&pem);
-#else
-
-int generate_signed_script( char * filename )
-{
- fprintf(stderr, "generate_script_signature() called without OpenSSL support
!\n");
- return -1;
+ return result;
}
-
-
-int verify_script_signature( char * filename )
-{
- fprintf(stderr, "verify_script_signature() called without OpenSSL support
!\n");
- return -1;
-}
-#endif
_______________________________________________
Openvas-commits mailing list
[email protected]
http://lists.wald.intevation.org/mailman/listinfo/openvas-commits