Plugin Architecture & Interface

As noted in the Tested Reference Implementations, GT.M includes the source code to 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 as ready to compile 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 source code by default resides in $gtm_dist/plugin/gtmcrypt/source.tar.

The reference implementation includes:

  1. A $gtm_dist/plugin/gtmcrypt/source.tar archive with all source files and scripts. The archive includes a Makefile to build/install the plugins 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. A Makefile to build and install each of the encryption plugin libraries. The Makefile conforms to the regular use pattern of "make && make install && make clean". Building the reference plugin libraries[8] requires a compiler and development libraries for GPG and OpenSSL. The reference plugins are:

    gpgagent.tab

    Call-out interface table to let MUMPS programs unobfuscate $gtm_passwd

    libgtmcrypt.so

    A symlink to the default encryption library

    libgtmcrypt_gcrypt_AES256CFB.so

    The reference plugin that leverages GPG for encryption using the AES256CFB algorithm

    libgtmcrypt_openssl_AES256CFB

    The reference plugin that leverages OpenSSL for encryption using the AES256CFB algorithm

    libgtmcryptutil.so

    A reference plugin support library

    libgtmtls.so

    The reference plugin that leverages OpenSSL for transport encryption features for the MUMPS language

    gtmpcrypt/maskpass

    Program to mask the password stored in $gtm_passwd

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[9]. 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.



[8] 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.

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