About the Secure Execution Engine SEE

The Secure Execution Engine (SEE) enables application code to run within the secure environment of a SEE-Ready HSM.

To use SEE, you must order and enable it as described in the User Guide. You must order the developer and user environments separately. SEE machines cannot be loaded on HSMs on which SEE is not enabled.

The CodeSafe Developer Kit includes the following:

Why use the Secure Execution Engine?

The main uses of cryptography are:

  • Integrity

  • Confidentiality

  • Authentication

Using an HSM to protect your cryptographic keys provides all these advantages. Your keys are only ever available in unencrypted form when they are loaded into the HSM: when key blobs are stored on the host, their integrity is protected by a Message Authentication Code (MAC). Access to the keys is controlled by using a Security World or an Operator Card Set (OCS). For additional information about the OCS, see the User Guide.

However, traditionally, the code that uses the keys remains on the server. This means that the code is open to attack. It is possible that the code could be modified in such a way as to leak important information or compromise your business rules. For example, it could fail to enforce such rules as “the books must balance” or “traders shall balance their positions by the close of trading”.

By implementing a solution with the SEE, you not only protect your cryptographic keys but also extend the security boundary to include your security critical code and data.

Using the techniques of code signing, data wrapping, and secure storage, the SEE enables you to maintain the confidentiality and integrity of application code and data and to bind them together so that only code in which you have confidence has access to confidential data.

Code integrity

In many secure applications, the primary concern is for the code to execute the correct sequence of operations and to not do anything else, such as leak information or key data. You can use the supplied Trusted Code Tool (tct2) to sign the HSM-side code and initialization data (if required) that make up a SEE machine. Application authors can use signatures to delegate authority to use key material and other resources.

Code confidentiality

When you use the SEE, the code that runs on an HSM can be stored in an encrypted format. The encryption key can be either a Triple Data Encryption Standard (Triple DES) or Advanced Encryption Standard (AES) key protected by either a Security World or an OCS.

Encrypted SEE machines are not currently supported for use with nShield Connects. When the SEEMachine binary is installed on the Connect itself for automated loading at boot, the SEE Confidentiality key is not available. However, when a client host loads a SEEMachine, it has access to the SEE Confidentiality key and can cause the binary to be decrypted. In this scenario, the Connect works fine with encrypted SEEMachine binaries.

The Access Control List (ACL) entry, UseAsLoaderKey, enables a key to be used to decrypt SEE objects on the HSM but that does not allow you to use it for standard decryption where the answer is returned to the host. This ensures that the code itself is not available “in the clear” outside of the HSM/SEE and; therefore, that any intellectual property embodied in the code is protected.

To load encrypted code, the user must first load the encryption key. Therefore, if the encryption key is protected by an OCS, only users with sufficient smart cards from that OCS can load the code. Because this SEE confidentiality key does not have decryption permissions (only the UseAsLoaderKey ACL entry), from a security standpoint, it is not essential that it be protected by an OCS.

HSM-protected SEE confidentiality keys can be useful in situations where the server or HSM is unexpectedly reset, because, in such a case, the SEE machine can then be reloaded without user intervention.

Data confidentiality

There are two main issues regarding data confidentiality:

  • Transient confidentiality of data in the running system

  • Long-term confidentiality of data when the code is not loaded.

The SEE protects the program’s information in the running system by enabling the programmer to determine the interface by which data can come in and out of the system and then rigorously enforce that interface.

Long-term confidentiality is preserved by using the non-volatile memory on the HSM. The SEE program can access this storage by using nCore API commands. Small quantities of highly sensitive information can be stored directly in the nonvolatile random access memory (NVRAM). When the amount of information to be stored exceeds the capacity of the NVRAM, data can be stored in an encrypted blob with a much smaller key stored in the NVRAM. This functionality allows the amount of secure storage to be limited only by the capacity of the host. For more information, see the nCore Developer Tutorial.

Data integrity

Confidential data is of little use if it can be changed by an attacker. Data stored in the HSM’s NVRAM could only be altered if the Access Control List (ACL) were to allow this to happen or if the physical security of the HSM were compromised. When a large volume of data is made into a blob, a hash of that blob can be stored in the NVRAM so that changes can be detected.

Another option for maintaining data that is not likely to change (such as root CA keys) is to place it in the application initialization space and then use code integrity techniques to protect the application initialization space.

Authentication and access control

A key feature of the SEE is the way that it can tie the integrity of the code to access control of the resources that the code uses.

The key-management architecture controls access to objects such as keys by means of ACLs. These lists specify sets of operations and verification keys that are used to check the credentials authorizing these operations.

With SEE, you can create keys that can only be used to encrypt or sign SEE machines (the SEE HSM-side code and, if required, its userdata). Encrypted application code is effectively bound to the encryption key, thereby ensuring that it can only be loaded onto an HSM on which you have already loaded the key. This functionality effectively gives you OCS protection on application code.

Encrypted SEE machines are not currently supported for use with nShield Connects. When the SEEMachine binary is installed on the Connect itself for automated loading at boot, the SEE Confidentiality key is not available. However, when a client host loads a SEEMachine, it has access to the SEE Confidentiality key and can cause the binary to be decrypted. In this scenario, the Connect works fine with encrypted SEEMachine binaries.

SEE also extends the authorization credentials to include signatures on code. This simple extension turns out to be very powerful. When a body of code issues a command to use a resource that is controlled by an ACL, it may present a certificate indicating that the signatures on the code should be examined by the ACL checking system. If the signature on the code verifies with one of the keys listed in the ACL, the operations delegated to that key can be carried out in that command.

Therefore, this extension of the authorization credentials means that you can create keys that can only be used by the SEE-resident code. These keys can be protected by the Security World or by OCSs.

The SEE code has access to the HSM’s NVRAM. Files stored in the HSM’s non-volatile memory also have ACLs. These ACLs describe not only who can access the file but what changes can be made to the file. For example, this feature enables you to create secure counters that you know can never be zeroed or that you know can be zeroed only by a trusted application running in the SEE.

How SEE works

A hardware security module maintains strict separation between the nShield core functions and the user code.

The application starts with the code for a SEE machine stored in a file on the host. A SEE machine is a binary executable of a type appropriate for the HSM. It communicates with the nShield Solo XC core by means of the interprocess communication (IPC).

Applications may be written in C and compiled to form the SEE machine itself. Alternatively, the SEE machine may consist of a language interpreter and the HSM code supplied as a script or byte code by means of userdata. For more information, see SEE and userdata.

If a separate host-side program is required, you can write the host-side code in C, using the nCore API. Alternatively, you can use the language of your choice. Example utilities written in Java are provided in the component jhsee in /opt/nfast/java/examples (Linux) or %NFAST_HOME%\java\examples (Windows).

These example utilities provide equivalent functionality to the C examples of similar names. You can adapt them as required. See the supplied Javadocs for full information about the Java example utilities.

The SEE machine can be signed, encrypted, or both, with the Trusted Code Tool (tct2). For more information about this command-line utility, see Utilities.

Encrypted SEE machines are not currently supported for use with nShield Connects. When the SEEMachine binary is installed on the Connect itself for automated loading at boot, the SEE Confidentiality key is not available. However, when a client host loads a SEEMachine, it has access to the SEE Confidentiality key and can cause the binary to be decrypted. In this scenario, the Connect works fine with encrypted SEEMachine binaries.

The first step is to load the SEE machine onto the HSM. The hardserver software, supplied on this installation media, automatically loads the SEE machine whenever the HSM is reset, provided that:

  • The HSM is SEE-Ready

    To determine whether your HSM is SEE-Ready, refer to the product data sheet for your HSM.
  • The HSM sets the enquiry level 4 HasSEE flag

  • A suitable machine image file is configured

  • The load_seemachine section of the configuration file is configured to enable the loading of SEE machines on startup.

You can perform this configuration with the loadsee-setup command-line utility. See Utilities.

For development purposes, you can also load SEE machines manually by running the loadmache command-line utility or, optionally, you can load SEE machines that require support from a host-side see-*-serv utility by specifying the -M option when you run the utility. See Utilities.

Code specifics

To use the functions provided by the SEE machine, the host application creates a SEE World, supplying the initialization data, which includes the HSM resident portion of the application code, initialization flags and any other SEE World initialization information required. The functions provided by the HSM-resident code can then be accessed by the SEE machine on command from the host-side portion of the application. The SEE World is a private work space and has a handle, an M_KeyID. As with other identifiers, this handle is associated with a ClientID. A host application can only access a SEEWorld on the connection that created the SEEWorld or on connections that have the same ClientID.

The CreateSEEWorld command takes a byte block called the SEE user data. This block can be used to pass initialization data when a SEE machine is started. This file also carries the signatures for the SEEWorld.

Refer to the nCore CodeSafe API Documentation for detailed information about the CreateSEEWorld command.


When the SEE machine has been initialized, the host application can call the functions that the SEE machine provides. These calls are sent using the nCore API command SEEJob.

For example, if you write code to implement a custom algorithm, the host application no longer calls the nCore API Encrypt command. Instead, it calls the encrypt function of the SEE machine. The algorithm in the SEE machine then asks the core for the key, uses the key to encrypt the message, and returns the result. This is explained in detail for the Solo XC in Designing SEE machines and SEE-ready HSMs.

The SEE machine can then make calls into the nShield core with the standard nCore API. The replies are returned directly to the SEE machine without ever leaving the protection of the HSM.

The SEE machine can access keys, or other objects that are protected by the HSM, only by making nCore API calls to the nShield core. HSM-side SEE code has the same privileges and access to the cryptographic functionality of the HSM as that given to the host-side programs using the nCore API. However, it is possible to create SEE application keys that can be used only by particular SEE applications and not by the host.


CodeSafe uses two command queues; The following diagram gives an overview of how they function. The hardserver sends commands to the input queue. The input queue looks at the commands and directs them to either the nCore API core or to the SEEWorld.

see queues
In this release you can only create a single SEEWorld for each HSM at any one time.

The nCore API core takes commands from the input queue, processes them in turn, and places them on the output queue. These commands may have come from the server or from the SEEWorld.

The output queue receives the completed jobs from the core. It determines whether the command was issued by the SEEWorld or the hardserver and sends the result to the appropriate place.

While any command sent to the SEEWorld may cause a number of calls to the nCore API core (and these calls circulate within the HSM), a given command only ever produces a single reply that is returned to the server. After the SEEWorld has completed the job, it returns a reply. The core returns this reply to the hardserver and on to the application; this is the reply to the SEEJob command, handled in exactly the same manner as for any other nCore API command.

The SEEJob reply is returned with Status_OK provided that the SEE machine returns a reply to the nShield core. The return of this kind of reply does not mean that the command itself was completed successfully in the SEE machine, only that communication between the core and the SEE machine was completed successfully. The SEE machine returns its own errors (if any) in the reply.

The application running in the SEEWorld does not have direct access to the user interface. Therefore, all interaction with the user must be performed by the host application. In some cases, especially when loading tokens that are protected by multiple smart cards, it can be useful to have the host application load an object and then pass control to the application in the Status_OK. You cannot pass the ObjectID because this is specific to the ClientID. Therefore, to pass control to the application in the Status_OK, you must use key tickets.

Key tickets were introduced to the nCore API specifically for SEE, although they can also be used to pass keys between different clients on the host. The client (or SEE application) that creates a key asks for a ticket for the key. It passes the ticket to the other client, which redeems the ticket for an ObjectID. There is only ever one copy of the object, and all commands have to comply with the ACL.

SEE system architecture

There are different architectural strategies that you can use when designing a CodeSafe SEE system, distinguished by the library they utilize:

see architecture

Before designing your CodeSafe SEE system, decide which architecture best suits your requirements:

  • glibc: This architecture allows the use of TCP sockets and a high performance GNU C library in CodeSafe. This makes it possible to communicate with a SEE machine using a generic approach.

    glibc can only be used if you are using an nShield Solo XC module and supports ISO C, POSIX, and System V standards.

    A design using this architecture is well suited for SEE machines that implement applications such as Web servers and proxies.

    If you are designing a CodeSafe Direct system, you must use the glibc architecture. The SEElib library is not supported for use with CodeSafe Direct.
    If you are designing a CodeSafe SEE system using the glibc library, you can use headers as normal for a Unix-based system (for example, stdio.h, stdlib.h, pthread.h).
  • SEElib: A design using this legacy architecture is well suited to protecting custom cryptography within a SEE machine. The A3A8 example program provides a simple demonstration of how to achieve this; see Designing SEE machines and SEE-ready HSMs for additional information.

    If you are designing a CodeSafe SEE system using the SEElib library, you can use the header file seelib.h, which contains wrapper functions for the software interrupts, in addition to a limited subset of the standard C library. See SEElib functions for additional information.

Unless you have a specific reason to use the SEElib architecture, Entrust recommend using the glibc architecture, as it provides a more familiar standards-based programming environment using standard socket and standard IO interfaces. Note that SEElib typically requires additional work on the host application to interface to the SEE code. This is not required when using the standards-based glibc approach.

SEE and userdata

What is userdata?

A userdata file can contain any data that is useful to the SEE machine. For example, you can use a CPIO archive to supply many different data files in a single directory structure (examples are provided in Designing SEE machines and SEE-ready HSMs.

All SEE machines built with glibc must be provided with a valid ASCII-format CPIO archive. This archive forms the base of the file system available to your SEE machine. Even if your SEE machine does not use this file system, you must still create and supply it with dummy userdata as a place-holder.

Creating userdata suitable for loading into the HSM

You can create a userdata file suitable for loading into the HSM by turning it into a SAR file with the tct2 command-line utility. Signing the userdata file in this way offers improved security.

SEE and Security Worlds

Within a Security World, the following actions may be configured to require authorization from the nShield Security Officer Key (KNSO) , or a key with authority delegated from the KNSO:

  • Allocation and forced freeing of nonvolatile memory

  • Setting the real-time clock

  • Enabling the run-time debugging options.

Each of these features can be enabled individually.

At Security World creation time, certificates may be created delegating authority from KNSO to keys protected by logical tokens which are split amongst the Administrator Card Set (ACS) in the usual way, but may require a different K/N threshold to reassemble. For example, you may wish to require that only one of five Administrator Cards be presented to set the real-time clock on an HSM, but three of them to replace the ACS.

The tools that create these certificates are:

  • KeySafe (version 2 and later)

  • Windows: The nShield CSP Wizard

  • new-world

  • the front panel (only on network-attached HSMs)

For more information about these tools, see the User Guide.

A Security World created using some older tools does not have any of these delegation certificates to support nonvolatile memory and real-time clock operations or to allow debugging of SEE applications. Therefore, such operations would require full KNSO authorization.

To sign or encrypt the HSM-side code, the signing and encryption keys must belong to the Security World to which the HSM belongs.

To test code outside a Security World, you can use the initunit command-line utility to remove the HSM from the Security World. In this case you cannot sign or encrypt your code, and the code cannot access keys protected by the Security World.

If you use the initunit command-line utility to initialize the HSM, any user can set the clock and create or free NVRAM files. This means that any user can free an existing file and allocate another file with the same name but with different contents or with a different ACL. Most security policies forbid this.