Author: bh
Date: 2007-07-02 17:45:42 +0200 (Mon, 02 Jul 2007)
New Revision: 243

Modified:
   trunk/openvas-libraries/ChangeLog
   trunk/openvas-libraries/include/libopenvas.h
   trunk/openvas-libraries/libopenvas/network.c
Log:
* libopenvas/network.c (OVAS_CONNECTION_FROM_FD): New. Macro to
determine the nessus_connection* given a nessus file descriptor
(nessus_register_connection, ovas_allocate_connection): Most of
nessus_register_connection is now in the new function
ovas_allocate_connection.
(set_gnutls_priorities): New.  Frontend for the other set_gnutls_*
functions.
(verify_peer_certificate): New.  Function to verify the peer
certificate
(open_SSL_connection): Use set_gnutls_priorities.
(ovas_server_context_new): New.  Function to allocate an
ovas_server_context_t
(ovas_server_context_free): New.  Function to free an
ovas_server_context_t
(ovas_server_context_attach): New.  Functin to set up SSL/TLS on a
socket with parameters from a ovas_server_context_t 

* include/libopenvas.h: Add declarations for the new functions and
types.  Always declare nessus_SSL_init.


Modified: trunk/openvas-libraries/ChangeLog
===================================================================
--- trunk/openvas-libraries/ChangeLog   2007-06-26 14:57:51 UTC (rev 242)
+++ trunk/openvas-libraries/ChangeLog   2007-07-02 15:45:42 UTC (rev 243)
@@ -1,3 +1,25 @@
+2007-07-02  Bernhard Herzog  <[EMAIL PROTECTED]>
+
+       * libopenvas/network.c (OVAS_CONNECTION_FROM_FD): New. Macro to
+       determine the nessus_connection* given a nessus file descriptor
+       (nessus_register_connection, ovas_allocate_connection): Most of
+       nessus_register_connection is now in the new function
+       ovas_allocate_connection.
+       (set_gnutls_priorities): New.  Frontend for the other set_gnutls_*
+       functions.
+       (verify_peer_certificate): New.  Function to verify the peer
+       certificate
+       (open_SSL_connection): Use set_gnutls_priorities.
+       (ovas_server_context_new): New.  Function to allocate an
+       ovas_server_context_t
+       (ovas_server_context_free): New.  Function to free an
+       ovas_server_context_t
+       (ovas_server_context_attach): New.  Functin to set up SSL/TLS on a
+       socket with parameters from a ovas_server_context_t 
+
+       * include/libopenvas.h: Add declarations for the new functions and
+       types.  Always declare nessus_SSL_init.
+
 2007-06-26  Jan-Oliver Wagner <[EMAIL PROTECTED]>
 
        * libhosts_gatherer/hg_add_hosts.c: Backported patch from original

Modified: trunk/openvas-libraries/include/libopenvas.h
===================================================================
--- trunk/openvas-libraries/include/libopenvas.h        2007-06-26 14:57:51 UTC 
(rev 242)
+++ trunk/openvas-libraries/include/libopenvas.h        2007-07-02 15:45:42 UTC 
(rev 243)
@@ -166,12 +166,12 @@
 ExtFunc void plug_set_ssl_cert(struct arglist*, char*);
 ExtFunc void plug_set_ssl_key(struct arglist*, char*);
 ExtFunc void plug_set_ssl_pem_password(struct arglist*, char*);
-ExtFunc int nessus_SSL_init(char*);
 ExtFunc void sslerror(char*);
 ExtFunc void nessus_install_passwd_cb(SSL_CTX*, char*);
 
 #endif
 
+ExtFunc int nessus_SSL_init(char*);
 
 
 ExtFunc void plug_add_dep(struct arglist *, char *, char *);
@@ -414,7 +414,20 @@
 ExtFunc               char*   stream_get_ascii_server_certificate(int);
 #endif
 
+struct ovas_server_context_s;
+typedef struct ovas_server_context_s * ovas_server_context_t;
 
+ovas_server_context_t ovas_server_context_new(int encaps,
+                                             const char* certfile,
+                                             const char* keyfile,
+                                             const char* passwd,
+                                             const char* cacertfile,
+                                             int force_pubkey_auth);
+void ovas_server_context_free(ovas_server_context_t);
+int ovas_open_server_socket(ovas_server_context_t);
+int ovas_server_context_attach(ovas_server_context_t ctx, int soc);
+
+
 ExtFunc        int     is_shell_command_present(char*);
 ExtFunc char*  find_in_path(char*, int);
 

Modified: trunk/openvas-libraries/libopenvas/network.c
===================================================================
--- trunk/openvas-libraries/libopenvas/network.c        2007-06-26 14:57:51 UTC 
(rev 242)
+++ trunk/openvas-libraries/libopenvas/network.c        2007-07-02 15:45:42 UTC 
(rev 243)
@@ -106,7 +106,10 @@
  */
 #define NESSUS_STREAM(x) (((x - NESSUS_FD_OFF) < NESSUS_FD_MAX) && ((x - 
NESSUS_FD_OFF) >=0))
 
+/* determine the nessus_connection* from the nessus fd */
+#define OVAS_CONNECTION_FROM_FD(fd) (connections + ((fd) - NESSUS_FD_OFF))
 
+
 static void
 renice_myself()
 {
@@ -231,29 +234,38 @@
 
 /* TLS FIXME: migrate this to TLS */
 ExtFunc int
-nessus_register_connection(int s, void *ssl)
+ovas_allocate_connection(int s, int transport)
 {
   int                  fd;
   nessus_connection    *p;
 
-  if (ssl != NULL)
-    {
-      nessus_perror("nessus_register_connection: ssl != NULL not supported");
-      return -1;
-    }
-
   if((fd = get_connection_fd()) < 0)
     return -1;
-  p = connections + (fd - NESSUS_FD_OFF);
+  p = OVAS_CONNECTION_FROM_FD(fd);
   p->timeout = TIMEOUT;                /* default value */
   p->port = 0;                 /* just used for debug */
   p->fd = s;
-  p->transport = (ssl != NULL) ? NESSUS_ENCAPS_SSLv23 : NESSUS_ENCAPS_IP;
+  p->transport = transport;
   p->last_err  = 0;
   return fd;
 }
 
 ExtFunc int
+nessus_register_connection(int s, void *ssl)
+{
+  if (ssl != NULL)
+    {
+      fprintf(stderr, "[%d] nessus_register_connection:"
+             " ssl != NULL not supported", getpid());
+      return -1;
+    }
+
+  return ovas_allocate_connection(s,
+                                 (ssl != NULL) ? NESSUS_ENCAPS_SSLv23
+                                               : NESSUS_ENCAPS_IP);
+}
+
+ExtFunc int
 nessus_deregister_connection(fd)
  int fd;
 {
@@ -510,6 +522,81 @@
   gnutls_mac_set_priority(session, mac_priority);
 }
 
+/*
+ * Sets the priorities for the GnuTLS session according to encaps, one
+ * of hte NESSUS_ENCAPS_* constants.
+ */
+static int
+set_gnutls_priorities(gnutls_session_t session, int encaps)
+{
+  switch (encaps)
+    {
+    case NESSUS_ENCAPS_SSLv3:
+      set_gnutls_sslv3(session);
+      break;
+    case NESSUS_ENCAPS_TLSv1:
+      set_gnutls_tlsv1(session);
+      break;
+    case NESSUS_ENCAPS_SSLv23: /* Compatibility mode */
+      set_gnutls_sslv23(session);
+      break;
+
+    default:
+#if DEBUG_SSL > 0
+      fprintf(stderr, "*Bug* at %s:%d. Unknown transport %d\n",
+             __FILE__, __LINE__, encaps);
+#endif
+      set_gnutls_sslv23(session);
+      break;
+    }
+
+  return 0;
+}
+
+/*
+ * Verifies the peer's certificate.  If the certificate is not valid or
+ * cannot be verified, the function prints diagnostics to stderr and
+ * returns -1.  If the certificate was verified successfully the
+ * function returns 0.
+ */
+static int
+verify_peer_certificate(gnutls_session_t session)
+{
+  static struct {int flag; const char * message;} messages[] = {
+    {GNUTLS_CERT_INVALID, "The peer certificate is invalid"},
+    {GNUTLS_CERT_REVOKED, "The peer certificate has been revoked"},
+    {GNUTLS_CERT_SIGNER_NOT_FOUND,
+     "The peer certificate doesn't have a known issuer"},
+    {GNUTLS_CERT_SIGNER_NOT_CA, "The peer certificate's issuer is not a CA"},
+    {GNUTLS_CERT_INSECURE_ALGORITHM,
+     "The peer certificate was signed using an insecure algorithm"},
+    {0, NULL},
+  };
+  int status;
+  int ret;
+  int i;
+
+  ret = gnutls_certificate_verify_peers2(session, &status);
+  if (ret < 0)
+    {
+      tlserror("gnutls_certificate_verify_peers2", ret);
+      return -1;
+    }
+
+  for (i = 0; messages[i].message != NULL; i++)
+    {
+      if (status & messages[i].flag)
+       fprintf(stderr, "[%d] failed to verify certificate: %s\n",
+               getpid(), messages[i].message);
+    }
+
+  if (status)
+    return -1;
+
+  return 0;
+}
+
+
 /* helper function copied from cli.c from GnuTLS
  * Reads a file into a gnutls_datum
  */
@@ -673,33 +760,16 @@
       return -1;
     }
 
-  switch (fp->transport)
-    {
-    case NESSUS_ENCAPS_SSLv3:
-      set_gnutls_sslv3(fp->tls_session);
-      break;
-    case NESSUS_ENCAPS_TLSv1:
-      set_gnutls_tlsv1(fp->tls_session);
-      break;
-    case NESSUS_ENCAPS_SSLv23: /* Compatibility mode */
-      set_gnutls_sslv23(fp->tls_session);
-      break;
+  /* set_gnutls_priorities handles NESSUS_ENCAPS_SSLv2 by falling back
+   * to NESSUS_ENCAPS_SSLv23.  However, this function
+   * (open_SSL_connection) is called only by open_stream_connection and
+   * open_stream_connection will exit with an error code if called with
+   * NESSUS_ENCAPS_SSLv2, so it should never end up calling
+   * open_SSL_connection with NESSUS_ENCAPS_SSLv2.
+   */
+  if (set_gnutls_priorities(fp->tls_session, fp->transport) < 0)
+    return -1;
 
-    default:
-#if DEBUG_SSL > 0
-      fprintf(stderr, "*Bug* at %s:%d. Unknown transport %d\n",
-             __FILE__, __LINE__, fp->transport);
-#endif
-      /* The default case also handles NESSUS_ENCAPS_SSLv2.  However,
-       * this function is called only by open_stream_connection and
-       * open_stream_connection will exit with an error code if called
-       * with NESSUS_ENCAPS_SSLv2, so it should never end up calling
-       * open_SSL_connection with NESSUS_ENCAPS_SSLv2.
-       */
-      set_gnutls_sslv23(fp->tls_session);
-      break;
-    }
-
   ret = gnutls_certificate_allocate_credentials(&(fp->tls_cred));
   if (ret < 0)
     {
@@ -1006,6 +1076,201 @@
 }
 
 
+/*
+ * Server socket functions
+ */
+
+struct ovas_server_context_s
+{
+  /* transport encapsulation to use */
+  int encaps;
+
+  /* whether to force public key authentication */
+  int force_pubkey_auth;
+
+  /* GnuTLS credentials */
+  gnutls_certificate_credentials_t tls_cred;
+};
+
+/*
+ * Creates a new ovas_server_context_t.  The parameter encaps should be
+ * one of the NESSUS_ENCAPS_* constants.  If any of the SSL
+ * encapsulations are used, the parameters certfile, keyfile, and cafile
+ * should be the filenames of the server certificate and corresponding
+ * key and the CA certificate.  The optional passwd parameter is used as
+ * the password to decrypt the keyfile if it is encrypted.
+ *
+ * The force_pubkey_auth parameter is a boolean controlling public key
+ * authentication of the client.  If force_pubkey_auth is true, the
+ * client must authenticate itself with a certificate.  Otherwise the
+ * client will be asked for a certificate but doesn't have to present
+ * one.
+ */
+ovas_server_context_t
+ovas_server_context_new(int encaps,
+                       const char* certfile,
+                       const char* keyfile,
+                       const char* passwd,
+                       const char* cafile,
+                       int force_pubkey_auth)
+{
+  ovas_server_context_t ctx = NULL;
+
+  if (nessus_SSL_init(NULL) < 0)
+    return NULL;
+
+  ctx = emalloc(sizeof(struct ovas_server_context_s));
+  if (ctx == NULL)
+    return NULL;
+
+  ctx->encaps = encaps;
+  ctx->force_pubkey_auth = force_pubkey_auth;
+
+  if (ctx->encaps != NESSUS_ENCAPS_IP)
+    {
+      int ret = gnutls_certificate_allocate_credentials(&(ctx->tls_cred));
+      if (ret < 0)
+       {
+         tlserror("gnutls_certificate_allocate_credentials", ret);
+         ctx->tls_cred = NULL;
+         goto fail;
+       }
+
+      if (certfile && keyfile)
+       {
+         if (load_cert_and_key(ctx->tls_cred, certfile, keyfile, passwd) < 0)
+           goto fail;
+       }
+
+      if (cafile != NULL)
+       {
+         ret = gnutls_certificate_set_x509_trust_file(ctx->tls_cred, cafile,
+                                                      GNUTLS_X509_FMT_PEM);
+         if (ret < 0)
+           {
+             tlserror("gnutls_certificate_set_x509_trust_file", ret);
+             goto fail;
+           }
+       }
+    }
+
+  return ctx;
+
+
+ fail:
+  ovas_server_context_free(ctx);
+  return NULL;
+}
+
+
+/*
+ * Frees the ovas_server_context_t instance ctx.  If ctx is NULL, nothing
+ * is done.
+ */
+void
+ovas_server_context_free(ovas_server_context_t ctx)
+{
+  if (ctx == NULL)
+    return;
+
+  if (ctx->tls_cred != NULL)
+    gnutls_certificate_free_credentials(ctx->tls_cred);
+
+  efree(&ctx);
+}
+
+/*
+ * Sets up SSL/TLS on the socket soc and returns a nessus file
+ * descriptor.  The parameters for the SSL/TLS layer are taken from ctx.
+ * Afterwards, the credentials of ctx are also referenced by the SSL/TLS
+ * objects associated with the nessus file descriptor.  This means that
+ * the context ctx must not be freed until the nessus file descriptor is
+ * closed.
+ *
+ * If the context's force_pubkey_auth member is true (!= 0), the client
+ * must provide a certificate.  If force_pubkey_auth is false, the
+ * client certificate is optional.  In any case, if the client provides
+ * a certificate, the certificate is verified.  If the verification
+ * fails, ovas_server_context_attach returns -1.
+ *
+ * ovas_server_context_attach returns the nessus file descriptor on
+ * success and -1 on failure.
+ */
+int
+ovas_server_context_attach(ovas_server_context_t ctx, int soc)
+{
+  int fd = -1;
+  nessus_connection * fp = NULL;
+  int status;
+  int ret;
+
+  fd = ovas_allocate_connection(soc, ctx->encaps);
+  if (fd < 0)
+    return -1;
+
+  fp = OVAS_CONNECTION_FROM_FD(fd);
+
+  if (fp->transport != NESSUS_ENCAPS_IP)
+    {
+      ret = gnutls_init(&(fp->tls_session), GNUTLS_SERVER);
+      if (ret < 0)
+       {
+         tlserror("gnutls_init", ret);
+         goto fail;
+       }
+
+      ret = set_gnutls_priorities(fp->tls_session, fp->transport);
+      if (ret < 0)
+       {
+         goto fail;
+       }
+
+      if (ctx->tls_cred)
+       {
+         /* *fp contains a field for the gnutls credentials.  We do not
+          * set it here because ctx->tls_cred is owned by ctx and
+          * copying it to fp->tls_cred would lead to it being freed
+          * when the connection is closed. */
+         ret = gnutls_credentials_set(fp->tls_session, GNUTLS_CRD_CERTIFICATE,
+                                      ctx->tls_cred);
+         if (ret < 0)
+           {
+             tlserror("gnutls_credentials_set", ret);
+             return -1;
+           }
+       }
+
+
+      /* request client certificate if any. */
+      gnutls_certificate_server_set_request(fp->tls_session,
+                                           ctx->force_pubkey_auth
+                                           ? GNUTLS_CERT_REQUIRE
+                                           : GNUTLS_CERT_REQUEST);
+
+      gnutls_transport_set_ptr(fp->tls_session,
+                              (gnutls_transport_ptr_t) fp->fd);
+      ret = gnutls_handshake(fp->tls_session);
+      if (ret < 0)
+       {
+         tlserror("gnutls_handshake", ret);
+         goto fail;
+       }
+
+      if (verify_peer_certificate(fp->tls_session) < 0)
+       {
+         goto fail;
+       }
+    }
+
+  return fd;
+
+ fail:
+  release_connection_fd(fd);
+  return -1;
+}
+
+
+
 /* TLS: This function is only used in one place,
  * openvas-plugins/plugins/ssl_ciphers/ssl_ciphers.c:145 (function
  * plugin_run).  The code there prints information about the

_______________________________________________
Openvas-commits mailing list
[email protected]
http://lists.wald.intevation.org/mailman/listinfo/openvas-commits

Reply via email to