Node Based Security Features

Node based security features include trusted hosts and executables, password encryption over the network and root authentication.

Trusted Hosts and Executables

Trusted hosts and trusted executables provide a straightforward method to limit hosts that can access EnFuzion nodes and user programs that EnFuzion is able to run. Only trusted hosts are allowed to access an EnFuzion node. Only trusted executables are executed by EnFuzion on the node.

The enfuzion.security File

Trusted hosts and trusted executables are specified in the enfuzion.security file. A system security file and a user specific security file can be located on each node host.

On Linux/Unix nodes, the system security file must be located in the directory /var/opt/enfuzion and the user security file in the directory ~/enfuzion/enfuzion.security.

On Windows NT nodes, the system security file must be located in the directory C:\enfuzion\enfuzion.security (your drive letter may be different). User security files are not supported on Windows NT.

Security files are handled as follows:

  • If the system security file exists, then the system security file is used and the user security file is ignored.

  • If the system security file is not found and the user security file exists, then the user security file is used.

  • If no security files are found, then all hosts and executables are trusted and no limitations are imposed on either hosts or executables.

If a security file exists, only hosts and executables specified in the file are trusted. An empty enfuzion.security file therefore specifies that no hosts and no executables are trusted.

Note: There are no special provisions for the local host address or for the 127.0.0.1 address. If the enfuzion.security file is enabled and access from the local host is required, then these addresses must be explicitly allowed.

File Syntax

Security files are text files containing a list of security specifications. Each line represents one specification. Comment lines begin with the 'pound mark', "#".

The syntax of a security specification is:


    <security_status>  <resource_type>  <resource_name_list>

  • <security_status>

    It can be either allow or deny. Allow specifies a list of trusted resources. Deny specifies a list of resources that are not trusted.

    For example, the following lines specify EnFuzion root hosts pluto and mini as trusted and host garfield as not trusted:

    
    allow host pluto, mini
        deny  host garfield
    
  • <resource_type>

    It provides the type of resource. <resource_type> can be either host or executable.

    For example, the following line specifies executables echo and ps as trusted:

    
    allow executable echo, ps
    
  • <resource_name_list>

    It gives a list of resource names. The names are separated by ','. The '*' denotes all resources of the given type. For example, the following line specifies all executables as trusted:

    
    allow executable *
    

If the <resource_type> is host, the names of hosts in a list can be either Internet IP addresses or DNS host names. Internet IP addresses have the format d.d.d.d[/m], where d is a decimal number or the wild card character '*'. The character '*' stands for any number. Parameter m can be used to specify network addresses. It determines the number of bits in the IP address that are used for address matching. A DNS host name consists of a host name and an optional domain name. The '*' as a host name denotes all hosts. For example, the following line specifies all hosts on the network 192.166.2 as trusted:


    allow host 192.166.2.*

To specify the same allowed host with network addressing:


    allow host 192.166.2.0/24

Note: The use of IP addresses is strongly recommended. If DNS host names are used instead, they can cause significant delays in EnFuzion operation. Due to DNS resolution, it can take up to several minutes to resolve an official host name on some networks.

The order of security specifications in a security file is important. All the specifications in the security file are verified for a given resource and the last status is taken as valid. For example, the following lines specify host strippy as trusted:


    deny host strippy
    allow host strippy

The following lines specify host strippy as not trusted:


    allow host strippy
    deny host strippy

The enfuzion.security file containing the following lines specifies all hosts running any executables as trusted:


    allow host *
    allow executable *

This is equivalent to not using a security file.

Security Considerations in Job Execution Commands

When trusted executables are used, note that all command paths must be fixed at the time of execution. For example, shell constructs that are interpreted after a command is submitted for execution are not allowed:


    execute $HOME/bin/enfecho

In the example above the complete path of the command is not determined until the line is executed by the shell. Therefore the security status of the command cannot be predetermined and the command is rejected. The command must be rewritten as follows:


    execute /home/myuser/bin/enfecho

User Defined Decryption Primitives

EnFuzion supports user defined decryption primitives. These primitives are implemented by using a dynamic library. The library contains user specific decryption methods. If the library exists, the primitives from the library are used instead of the default EnFuzion primitives.

This feature is supported only on Windows NT/2000/XP.

Overview of the Dynamic Library

The dynamic library for user defined decryption supports two tasks, the decryption of user passwords and the decryption of the EnFuzion security file, enfuzion.security. The library provides an interface which specifies decryption functions called by EnFuzion.

The library must have the filename enfuser.dll. The .dll file which is usually in the directory C:\enfuzion\bin must be in the search path of each EnFuzion node.

The library is loaded at program startup. If a new version of the library is provided by the user, all EnFuzion programs that use the library must be restarted. The programs affected are Starter Service and node server.

Interface

The library supports decryption of passwords and decryption of the file enfuzion.security.

The following interface functions are defined for enfuser.dll:


    int decryptPassword(
         char *passin,
         int inlen,
         char *passout,
         int outlen);

    void *openFileDecryption(
         char *filename);

    int readNextDecryptedLine(
         void *fid,
         char *buffer,
         int buflen);

    int closeFileDecryption(
         void *fid);

If a function is not found in enfuser.dll, then its default version is called.

A binary dump of enfuser.dll is similar to the following output:


    d:\enfuzion\bin> dumpbin -exports enfuser.dll

    Dump of file enfuser.dll
    ...
    File Type: DLL

           Section contains the following Exports for secdemodll.dll
    ...
            ordinal hint   name

                  5    0   __DebuggerHookData  (000021BC)
                  3    1   _closeFileDecryption  (000014BE)
                  4    2   _decryptPassword  (000014D7)
                  1    3   _openFileDecryption  (00001480)
                  2    4   _readNextDecryptedLine  (00001495)

Notice that the names of library functions are preceded by an underscore, "_".

Because enfuser.dll is used also by processes running in the background, functions should not write to standard output or standard error streams.

Details of the interface functions are described in the next section.

Decryption of Passwords

Passwords to access remote machines are specified in the network configuration file, usually enfuzion.nodes. These passwords can be in a clear text form or encoded by EnFuzion, as described in the Section called Encrypted Passwords in enfuzion.nodes in Chapter 6.

The user can replace clear text passwords in enfuzion.nodes with encrypted passwords. Encrypted passwords must consist of non-white, printable ASCII characters. These passwords will be decrypted by calling function decryptPassword() from the dynamic library enfuser.dll. If enfuser.dll is not found or decryptPassword() is not defined, then no user decryption will be performed.

Function decryptPassword() provides the following interface:


    int decryptPassword(char *passin, int inlen, char *passout, int outlen);

The passin pointer points to the user encrypted password from enfuzion.nodes. The inlen parameter is the number of valid characters in passin. The passout pointer points to the decrypted password. The decrypted password must contain non-white, printable ASCII characters, terminated by a null character, '\0'. This string will be used as a password to perform a login on the remote host. The outlen parameter is the length of the passout buffer, available for the decrypted password. The function implementation must handle passout buffer overflows. The function returns 0 on success or a negative user defined error code otherwise.

Currently, EnFuzion provides a passout buffer size of 1024 characters, i.e., outlen equals 1024.

User encrypted passwords can be decrypted by EnFuzion, but not vice-versa.

Decryption of enfuzion.security

On Windows NT/2000/XP, the EnFuzion security file enfuzion.security can be encrypted by the user. EnFuzion uses the following functions from enfuser.dll to decrypt the file.


    void *openFileDecryption(char *filename);

This function returns a handle to identify an encrypted file. NULL is returned on error. Currently, EnFuzion calls openFileDecryption() with the filename parameter containing the absolute path of the enfuzion.security file on the host.


    int readNextDecryptedLine(void *fid, char *buffer, int buflen);

This function reads the next line from the file and returns the number of bytes read or a negative number if error. A return value of 0 indicates an end of file. Currently, EnFuzion provides a buffer of size 1024 characters, i.e., buflen equals 1024. fid is equal to the handle, returned by a previous call to openFileDecryption().


    int closeFileDecryption(void *fid);

Closes the handle. Returns 0 on success and -1 otherwise. fid equals to the handle, returned by a previous call to openFileDecryption().

If a function is not defined in enfuser.dll, then its default version with no decryption is called.

Library Template

This example provides a library template of function implementations. The template provides no decryption and handles clear text.


    /*
     * Sample implementation of security dll: "enfuser.dll"
     */

    #include <stdio.h>
    #include <string.h>

    /*
     * Decrypt password
     * return 0 on success
     *       -1 on error
     */
    int _export decryptPassword(char *password, int passlen,
                            char *decryptedpassword, int decpasslen)
    {
      if (strlen(password) > decpasslen) {
        return -1;
      }
      strcpy(decryptedpassword, password);
      return 0;
    }

    /*
     * Return a handle to decrypted file
     * or NULL on error.
     */
    void * _export openFileDecryption(char *filename)
    {
      return(fopen(filename, "r"));
    }

    /*
     * Read next decrypted line
     * Return number of characters read
     */
    int _export readNextDecryptedLine(void *fid, char *outbuf, int outbuflen)
    {
       if (fgets(outbuf, outbuflen, fid) == NULL) {
         return 0;
       }
       return strlen(outbuf);
    }

    /*
     * Close handle to decrypted file
     * Return 0 on success
     *        -1 on error
     */
    int _export closeFileDecryption(void *fid)
    {
      if (fclose(fid) != 0) {
        return -1;
      } 
      return 0;
    }

Root Authentication

EnFuzion root authentication is based on public/private key encryption. This authentication strengthens network security on nodes, since it assures that only authorized root hosts are able to use remote nodes. Root authentication is supported only on Windows NT/2000/XP nodes.

Root authentication works as follows. The root host distributes its public keys to the nodes. When public keys are present on a node, the node initiates the authentication of the root's identity. If the root host does not have the matching private key, authentication fails and the connection to the root host is terminated.

Private and public keys can be generated and distributed with the EnFuzion provided Enfkey utility, described below.

EnFuzion provides a library to implement the root authentication capability. This authentication library can be replaced with a user defined library, which might be required in certain high security environments.

The following sections describe the Enfkey utility, the process of generating and distributing the keys, the EnFuzion provided authentication library and how to implement a user defined authentication library.

The Enfkey Utility

The Enfkey utility generates a public/private key pair. If a user defined authentication library is provided, enfkey uses that library.

The Enfkey program uses the following syntax:


    enfkey keygen

This generates new public and private keys for the system where enfkey is executed. The IP address of the system that generated the keys is also printed to the standard output.

Example:

For the default EnFuzion authentication library, the keys are placed in file enf_key.priv. A sample file contents is:


    Id=172.12.85.23 
    PrivKey=11773C2ADB11EBE6FBE7911056C3A1E53A4C7F4B 
    PublicKey=97F035A7B89B95CBA91F3EE1E3343293CACDDECD59D7 
    CA381490532BB118ECD204703702137E80CFB89EA622CE153699DE 
    2060CDB787A153B6321CFC376C7C97913D3C1795015A10FC3C9935 
    236DD68C2C3BC11E9142787600361F1AEF9EC9B82137270E1F175A 
    A1F52836030776AE0DA6FE5E4CB5E1C16C0EC60058DC0F47F1
Id designates the IP address of the system where the keys were created. PrivKey and PublicKey contain private and public keys, respectively.

Generation and Installation of Keys

The procedure to generate the keys on the root system and store the public key on the node is described below.

  • On the root, generate its public/private pair of keys.

    
    enfkey keygen
    

  • On the root, make a duplicate of the enf_key.priv file and remove the PrivKey field with the private key.

  • Copy the duplicate enf_key.priv file with the private key removed to the node.

  • On the node, install the EnFuzion root public key by adding the contents of the duplicate enf_key.priv file to the enfuzion.key.

EnFuzion Provided Authentication Library

The default authentication library provided with EnFuzion employs the widely used SSL encryption library. When using the default implementation on a Linux/Unix EnFuzion root system, OpenSSL must be installed. If required, the authentication library can be replaced with a user provided library (see the Section called User Defined Authentication Primitives for more information).

The EnFuzion root authentication is performed, if at least one public key is installed. Otherwise, any EnFuzion root system can access the node.

The default authentication library stores public keys on nodes in file enfuzion.key. Only Windows NT/2000/XP platforms are supported. The file is located in the EnFuzion directory, which is C:\enfuzion by default.

Private keys on EnFuzion root systems are stored in file enfuzion.pkey. Any EnFuzion supported platform can act as the authenticated root. File enfuzion.pkey is located in the EnFuzion config directory.

The user can manually add public keys to the enfuzion.key file on the node. To add a public key, make a duplicate of enf_key.priv file on the root, delete the private key line in the duplicate, copy the modified duplicate file to the node and append the file to the enfuzion.key file on the node. The enfuzion.key file can contain multiple public keys.

User Defined Authentication Primitives

Default EnFuzion provided authentication primitives can changed by replacing the default authentication library provided with EnFuzion with a custom library. The custom library must be available both on the root host and on all node hosts. This section describes the interface used by the authentication library.

Overview of the Dynamic Library

The dynamic library provides primitives for root authentication called by EnFuzion. It supports the following tasks: generation of private/public keys, and adding and removing keys to a machine configuration. The library must have the filename enfauth.dll on Windows or enfauth.so on Linux/Unix hosts. The dynamic library file, which is usually in the directory /enfuzion/bin on Windows NT/2000/XP, must be in the search path of each EnFuzion node.

Interface

The following interface functions are defined for the library:


    int CryptoCapabilities();

    char *CryptoInformation();

    int CryptoSignBuffer(
         char  *fromIP,
         char  *buff,
         int    len,
         char **dest);

    int CryptoVerifyBuffer(
         char  *fromIP,
         char  *originalBuff,
         int    len,
         char  *signatureBuffer);

    int CryptoGenKeys(
         char **PublicKey,
         char **PrivateKey);

    int CryptoAddKey(
         char  *fromIP,
         char  *PublicKey,
         char  *PrivateKey);

    int CryptoRemoveKey(
         char  *forIP);

If a function is not found in enfauth.*, then its default version is used. A binary dump of enfauth.dll on Windows produces the following output:


    d:\enfuzion\bin> dumpbin enfauth.dll /EXPORTS

    Dump of file enfauth.dll
    ...
    File Type: DLL

    ...

    ordinal hint RVA      name

          1    0 00001023 CryptoAddKey
          2    1 00001019 CryptoCapabilities
          3    2 0000100A CryptoGenKeys
          4    3 00001014 CryptoRemoveKey
          5    4 00001028 CryptoSignBuffer
          6    5 0000100F CryptoVerifyBuffer
          7    5 0000102D CryptoInformation

Windows note:

The function name has no decorations. The function must be implemented with the STDCALL calling convention. The library must be compiled as a multi threaded DLL.

Linux/Unix note:

Because enfauth.dll/so is used by processes running in the background, functions must not write to standard output or standard error streams.

Returning Status

Each library function must return status. If the function is successful it must return 0. In the case of an error, the function must return one of the following error codes.

List of valid error codes:


    #define AUTH_ERROR_NO_CAPABILITIES -1
    #define AUTH_ERROR_NOT_TRUSTED     -3
    #define AUTH_ERROR_NO_NETWORK      -4
    #define AUTH_ERROR_CANNOT_READ     -5
    #define AUTH_ERROR_CANNOT_SEND     -6
    #define AUTH_ERROR_NO_PRIVATEKEY   -11
    #define AUTH_ERROR_NO_PUBLICKEY    -12

Defining Library Capabilities


    int CryptoCapabilities();

The function returns an integer defining which functions from the library can be used.

The following flags are valid:


    #define AUTH_CAP_SIGN       1
    #define AUTH_CAP_VERIFY     2
    #define AUTH_CAP_ADDKEY     4
    #define AUTH_CAP_REMOVEKEY  8
    #define AUTH_CAP_GENKEY     16

Displaying Library Information


    char *CryptoInformation();

The function returns a static string with information about the library. The information is recorded in EnFuzion logs.

Signing Buffer


    int CryptoSignBuffer(
         char  *fromIP,
         char  *buff,
         int    len,
         char **dest);

During the authentication sequence, the root host is requested to encode random data. EnFuzion calls CryptoSignBuffer to perform this task.

The parameter fromIP holds an IP number as text (e.g. "172.20.93.19") defining who requested the signature. Random data and the length of the buffer are held in the next two parameters. This function stores encoded data in a text string dest.

Verifying Returned Buffer


    int CryptoVerifyBuffer(
         char  *fromIP,
         char  *buff,
         int    len,
         char  *signatureBuffer);

A node that authenticates the root host needs to verify the returned result. EnFuzion calls CryptoVerifyBuffer to perform this task. Input parameter fromIP defines the root IP number as text (e.g. "172.20.93.18"). Parameters buff and len define data. The last parameter is the text string received from the root.

Adding Keys to a Node or a Root Host


    int CryptoAddKey(
         char  *assignedIP,
         char  *PublicKey,
         char  *PrivateKey);

In order to perform authentication, the root must store its private and public keys and the node host must store the root's public key. EnFuzion calls the function CryptoAddKey on every node with the input parameters PublicKey and PrivateKey set to NULL. If CryptoAddKey is called on the root machine PublicKey and PrivateKey are not NULL. Parameter assignedIP points to the IP as text (e.g. "172.20.93.18") identifying which computer owns this public key. The function is also called on the root host if assignedIP points to the local host. This time the private key is also passed in the parameters.

Removing Keys from a Node


    int CryptoRemoveKey(char *forIP);

The function CryptoRemoveKey removes a key. Sometimes keys have to be replaced on a particular host. In order to retain access to that host, the user must first install the new keys and then remove the old ones. Parameter forIP points to the text IP (e.g. "172.20.93.18") of the owner of the public key that the user wants to remove.

Generating New Keys


    int CryptoGenKeys(char **PublicKey,
         char **PrivateKey);

Newly generated keys can be installed on the root and on node hosts. The function CryptoGenKeys must allocate space and copy the private and public keys to that space. These keys must be in text form. EnFuzion releases buffer space when they are no longer needed.

Library Template

The following example is a library template. The template provides only a framework, but no real encryption or decryption .

Example:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>


#ifdef WIN32
#include <windows.h>
#define CALL_CONV __stdcall
#else
#include <sys/stat.h>
#include <sys/types.h>
#include <netdb.h>
#include <unistd.h>
#define CALL_CONV 
#endif

static char *lib_info_text = "enFuzion authentication library template";

char* CALL_CONV CryptoInformation()
{  
  return lib_info_text;
}

int CALL_CONV CryptoCapabilities()
{
  return 0x01 | 0x02 | 0x04 | 0x08 | 0x10;
}

int signBuff(char  *buff, 
             int    len, 
             char **dest,
             int    key) 
{
  return 0;
}

int getKey(char *ipBuff, int *keynum)
{
  FILE *file;
  char iptmp[256];

  file = fopen("/enftmp.key", "r");
  if (file) {
    while (!feof(file)) {
      fscanf(file, "%s %d\n", iptmp, keynum);
      if (strcmp(iptmp, ipBuff) == 0) {
        fclose(file);
        return 0;
      }
    }
    fclose(file);
  }
  return -1; 
}

int CALL_CONV CryptoSignBuffer(char  *fromIP, 
                     char  *buff, 
                     int    len, 
                     char **dest)
{
  struct hostent *hostent ;
  int            ret, i;
  char           tmpBuff[256];
  unsigned char  sig[5];

  gethostname(tmpBuff, 256);
  hostent = gethostbyname(tmpBuff);
  for(i = 0; i < 4; i++)  sig[i] = hostent->h_addr[i];
    sprintf(tmpBuff, "%u.%u.%u.%u", sig[0], sig[1], sig[2], sig[3]);	

  /* write private file for license issuer */

  ret = getKey(tmpBuff, &i);
  if (ret) {
    /* return error - no private key */
    return -11;
  }

  /* no encryption - return private key since public key is same */
  sprintf(tmpBuff, "%d", i);
  *dest = strdup(tmpBuff);

  return 0;
}

int CALL_CONV CryptoVerifyBuffer(
                       char  *fromIP, 
                       char  *originalBuff, 
                       int    len, 
                       char  *signatureBuffer)
{
  int           ret, i;
  char          tmpBuff[256];

  ret = getKey(fromIP, &i);
  if (ret) {
    /*return error - no public key*/
    return -12;
  }

  sprintf(tmpBuff, "%d", i);

  /* verify the "signature" ...*/
  if (strcmp(signatureBuffer, tmpBuff) == 0)
  {
    return 0;
  }  
  /* return error - not trusted*/  
  return -3;
}

int CALL_CONV CryptoGenKeys(char **PublicKey, char **PrivateKey)
{
  struct hostent *hostent ;
  int     i;
  char      temp[256];
  unsigned char sig[5];

  gethostname(temp, 256);
  hostent = gethostbyname(temp);
  if (hostent)
  {
   /* write private file for license issuer */
    for(i = 0; i < 4; i++)  sig[i] = hostent->h_addr[i];
      sprintf(temp, "%u.%u.%u.%u", sig[0], sig[1], sig[2], sig[3]);	

    srand(time(0));
    i = rand();
    sprintf(temp, "%d", i);

    *PublicKey = strdup(temp);
    *PrivateKey = strdup(temp);

    return 0;
  }

  /* return error - no capabilities */  
  return -1;
  
}

/* install public key or private key */
int CALL_CONV CryptoAddKey(char *forIP, char *PublicKey, char *PrivateKey) 
{
  FILE *file;

  if (PrivateKey != 0 &&
      PublicKey  != 0)
  {
    /* final stage - we are on root */
    file = fopen("/enftmp.key", "a");
    if (file) {
      fprintf(file,"%s %s\n", forIP, PublicKey);
      fclose(file);
    }
  } else if (PublicKey != 0) 
  {
    /* install only public keys */
    file = fopen("/enftmp.key", "a");
    if (file) {
      fprintf(file,"%s %s\n", forIP, PublicKey);
      fclose(file);
    }
  }
  return 0;
}

int CALL_CONV CryptoRemoveKey(char *forIP) /*remove key*/
{
  char buff[256];
  fpos_t pos;
  int   i;
  FILE  *file;

  file = fopen("/enftmp.key", "r+");
  while (file && 
        !feof(file))
  {
    fgetpos(file, &pos);

    if  (fscanf(file,"%s %d\n", buff, &i) > 0 &&
         strcmp(buff, forIP) == 0)
    {
      buff[0] = '#';
      fsetpos(file, &pos);
      fwrite(buff, 1, 1, file);
      break;
    }
  }
  if (file)
    fclose(file);
  return 0;
}