Plugin Architecture & Interface

As noted in the Tested Reference Implementations, GT.M includes a reference implementation that uses widely available encryption packages. It is your choice: you can decide to use the packages that FIS tested GT.M against, or you can choose to interface GT.M to another package of your choice. As noted earlier, FIS neither recommends nor supports any specific package (not even those that we test against) and you should ensure that you have confidence in and support for whichever package that you intend to use in production. The reference implementation is provided compiled as ready to run object code as well as source code that you can customize to meet your needs.

Building the reference implementation from source code requires standard development tools for your platform, including C compiler, make, ld, standard header files, header files for encryption libraries, etc.

This section discusses the architecture of and interface between GT.M and the plugin. You must ensure that any plugin you provide presents the same interface to GT.M as the reference implementation.

Packaging

The reference implementation by default resides in $gtm_dist/plugin/gtmcrypt.

The reference implementation includes:

  1. A $gtm_dist/plugin/gtmcrypt sub-directory with all source files and scripts. The scripts include those needed to build/install libgtmcrypt.so and "helper" scripts, for example, add_db_key.sh. A brief description of these scripts is as follows:

    show_install_config.sh

    Reports the cryptographic library and cipher that a GT.M process would use, from $gtm_crypt_plugin, if it has a value and otherwise from the name of the library linked to by libgtmcrypt.so.

    gen_sym_hash.sh

    Uses show_install_config.sh to identify the currently installed encryption configuration so that it can generate the appropriate cryptographic hash for the provided symmetric key.

    import_and_sign_key.sh

    Imports and signs one another's public keys.

    gen_sym_key.sh

    Generates a symmetric cipher key for others to use in encrypting a database file.

    encrypt_sign_db_key.sh

    Uses a private key to decrypt the symmetric cipher key , encrypts it with other's public key, and signs it with the private key.

    add_db_key.sh

    Adds a key to the master key file.

  2. The plugin interface that GT.M expects is defined in gtmcrypt_interface.h. Never modify this file - it defines the interface that the plugin must provide.

  3. $gtm_dist/plugin/libgtmcrypt.so[10] is the shared library containing the executables which is dynamically linked by GT.M and which in turn calls the encryption packages. If the $gtm_dist/utf8 directory exists, then it should contain a symbolic link to ../plugin.

  4. Source code is provided in the file $gtm_dist/plugin/gtmcrypt/source.tar which includes the following scripts to compile and install libgtmcrypt.so.

    build.sh

    Compiles libgtmcrypt.so from the source code and has the following parameters:

    • gcrypt or openssl: specifies the cryptographic library

    • d or p: Use p for production and d for debugging

    • AES256CFB or BLOWFISHCFB (optional): This optional parameter allows you to specify the cipher with which to build the encryption plugin. The default is AES256CFB.

    install.sh

    Installs libgtmcrypt.so and has the following parameters:

    • gcrypt or openssl: specifies the cryptographic library

    • AES256CFB or BLOWFISHCFB (optional): This optional parameter allows you to specify the cipher with which to build the encryption plugin. The default is AES256CFB.

Extensions to the GT.M External Interface

GT.M provides additional C structure types (in the gtmxc_types.h file):

  1. gtmcrypt_key_t - a datatype that is a handle to a key. The GT.M database engine itself does not manipulate keys. The plug-in keeps the keys, and provides handles to keys that the GT.M database engine uses to refer to keys.

  2. xc_fileid_ptr_t - a pointer to a structure maintained by GT.M to uniquely identify a file. Note that a file may have multiple names - not only as a consequence of absolute and relative path names, but also because of symbolic links and also because a file system can be mounted at more than one place in the file name hierarchy. GT.M needs to be able to uniquely identify files.

Although not required to be used by a customized plugin implementation, GT.M provides (and the reference implementation uses) the following functions for uniquely identifying files:

  1. xc_status_t gtm_filename_to_id(xc_string_t *filename, xc_fileid_ptr_t *fileid) - function that takes a file name and provides the file id structure for that file.

  2. xc_status_t gtm_is_file_identical(xc_fileid_ptr_t fileid1, xc_fileid_ptr_t fileid2) - function that determines whether two file ids map to the same file.

  3. gtm_xcfileid_free(xc_fileid_ptr_t fileid) - function to release a file id structure.

Operation

Mumps, MUPIP and DSE processes dynamically link to the plugin interface functions that reside in the shared library. The functions serve as software "shims" to interface with an encryption library such as libmcrypt or libgpgme / libgcrypt.

The plugin interface functions are:

  1. gtmcrypt_init()

  2. gtmcrypt_getkey_by_name()

  3. gtmcrypt_getkey_by_hash()

  4. gtmcrypt_hash_gen()

  5. gtmcrypt_encrypt()

  6. gtmcrypt_decrypt()

  7. gtmcrypt_close()

  8. and gtmcrypt_strerror()

A GT.M database consists of multiple database files, each of which has its own encryption key, although you can use the same key for multiple files. Thus, the gtmcrypt* functions are capable of managing multiple keys for multiple database files. Prototypes for these functions are in gtmcrypt_interface.h.

The core plugin interface functions, all of which return a value of type xc_status_t are:

  • gtmcrypt_init() performs initialization. If the environment variable $gtm_passwd exists and has an empty string value, GT.M calls gtmcrypt_init() before the first M program is loaded; otherwise it calls gtmcrypt_init() when it attempts the first operation on an encrypted database file.

  • Generally, gtmcrypt_getkey_by_hash or, for MUPIP CREATE, gtmcrypt_getkey_by_name perform key acquisition, and place the keys where gtmcrypt_decrypt() and gtmcrypt_encrypt() can find them when they are called.

  • Whenever GT.M needs to decode a block of bytes, it calls gtmcrypt_decrypt() to decode the encrypted data. At the level at which GT.M database encryption operates, it does not matter what the data is - numeric data, string data whether in M or UTF-8 mode and whether or not modified by a collation algorithm. Encryption and decryption simply operate on a series of bytes.

  • Whenever GT.M needs to encrypt a block of bytes, it calls gtmcrypt_encrypt() to encrypt the data.

  • If encryption has been used (if gtmcrypt_init() was previously called and returned success), GT.M calls gtmcrypt_close() at process exit and before generating a core file. gtmcrypt_close() must erase keys in memory to ensure that no cleartext keys are visible in the core file.

More detailed descriptions follow.

  • gtmcrypt_key_t *gtmcrypt_getkey_by_name(xc_string_t *filename) - MUPIP CREATE uses this function to get the key for a database file. This function searches for the given filename in the memory key ring and returns a handle to its symmetric cipher key. If there is more than one entry for the given filename , the reference implementation returns the entry matching the last occurrence of that filename in the master key file.

  • xc_status_t gtmcrypt_hash_gen(gtmcrypt_key_t *key, xc_string_t *hash) - MUPIP CREATE uses this function to generate a hash from the key then copies that hash into the database file header. The first parameter is a handle to the key and the second parameter points to 256 byte buffer. In the event the hash algorithm used provides hashes smaller than 256 bytes, gtmcrypt_hash_gen() must fill any unused space in the 256 byte buffer with zeros.

  • gtmcrypt_key_t *gtmcrypt_getkey_by_hash(xc_string_t *hash) - GT.M uses this function at database file open time to obtain the correct key using its hash from the database file header. This function searches for the given hash in the memory key ring and returns a handle to the matching symmetric cipher key. MUPIP LOAD, MUPIP RESTORE, MUPIP EXTRACT, MUPIP JOURNAL and MUPIP BACKUP -BYTESTREAM all use this to find keys corresponding to the current or prior databases from which the files they use for input were derived.

  • xc_status_t gtmcrypt_encrypt(gtmcrypt_key_t *key, xc_string_t *inbuf, xc_string_t *outbuf) and xc_status_t gtmcrypt_decrypt(gtmcrypt_key_t *key, xc_string_t *inbuf, xc_string_t *outbuf)- GT.M uses these functions to encrypt and decrypt data. The first parameter is a handle to the symmetric cipher key, the second a pointer to the block of data to encrypt or decrypt, and the third a pointer to the resulting block of encrypted or decrypted data. Using the appropriate key (same key for a symmetric cipher), gtmcrypt_decrypt() must be able to decrypt any data buffer encrypted by gtmcrypt_encrypt(), otherwise the encrypted data is rendered unrecoverable[11]. As discussed earlier, GT.M requires the encrypted and cleartext versions of a string to have the same length.

  • char *gtmcrypt_strerror() - GT.M uses this function to retrieve addtional error context from the plug-in after the plug-in returns an error status. This function returns a pointer to additional text related to the last error that occurred. GT.M displays this text as part of an error report. In a case where an error has no additional context or description, this function returns a null string.

The complete source code for reference implementations of these functions is provided, licensed under the same terms as GT.M. You are at liberty to modify them to suit your specific GT.M database encryption needs. Check your GT.M license if you wish to consider redistributing your changes to others.



[10] Different computing platforms may use different file extensions for shared libraries, including .sl and .dll. This document uses .so for readability, but the actual name may vary on your platform.

[11] Such a failure in the cipher will likely appear to GT.M as a damaged database.