SEE API documentation

SEElib is an API that enables an SEE machine to both execute nCore API commands and to accept messages from the host machine via the SEEJobs protocol. It is supported both in CodeSafe 5 and in CodeSafe for previous HSM models.

The SEElib API is provided as a library seelib.a that can be found in the rootfs after install. Its install location is /opt/nfast/c/csd5/lib-ppc64-linux-musl/seelib.a on Linux.

SEElib functions

SEElib_init

extern void SEElib_init(void);

This function initializes the SEElib library.

This function does not return on error.

SEElib_ReadUserData

extern int SEElib_ReadUserData ( M_Word offset, unsigned char *buf, M_Word len );

This function reads selected bytes from the UserData block, starting at offset bytes in and continuing for len bytes. It returns an M_Status value.

As the concept of a separate UserData input does not exist in CodeSafe 5, for backwards compatibility this function is supported as reading a file located inside the container (/etc/codesafe.userdata) which must be added at that path when the container image is constructed.

SEElib_ReleaseUserData

extern void SEElib_ReleaseUserData(void);

In CodeSafe 5 this function does not do anything. It is only present for backwards compatibilty.

SEElib_InitComplete

extern void SEElib_InitComplete( M_Word status );

In CodeSafe 5 this function does not do anything. It is only present for backwards compatibility.

SEElib_StartTransactListener

extern void SEElib_StartTransactListener(void);

This function starts the thread that listens for SEElib_Transact calls and dispatches them. This function must be called before any use is made of SEElib_Transact.

SEElib_Transact

extern int SEElib_Transact(struct M_Command *cmd, struct M_Reply *buf);

This function marshals a command, submits it, waits for the response, and unmarshals it into a reply structure.

SEElib_MarshalSendCommand

extern int SEElib_MarshalSendCommand(M_Command *cmd);

This function marshals a command and places it on the input queue for processing by the nShield core.

The command takes a reference to an M_Command structure, as described in the nCore CodeSafe API Documentation.

The SEE machine can submit any of the nCore API commands listed in the Basic commands and Key-Management commands sections of the nCore CodeSafe API Documentation except:

  • RetryFailedModule

  • GetWhichModule

  • MergeKeyIDs.

If the SEE machine attempts to submit one of these commands, the nShield core returns a response with the status code NotAvailable.

The SEElib_MarshalSendCommand function returns an M_Status value. This value is OK if the command was marshalled and transferred to the nShield core correctly.

Do not mix calls to SEE_Transact() and SEElib_MarshalSendCommand() and SEElib_GetUnmarshalResponse(), because the replies may be misdirected.

SEElib_GetUnmarshalResponse

extern int SEElib_GetUnmarshalResponse(M_Reply *buf);

If there is a reply in the input queue for this SEE world, this function returns the first job in the queue. Otherwise, it blocks and waits for the nShield core to return a job.

On return, M_Reply contains the unmarshalled reply.

The SEElib_GetUnmarshalResponse function returns an M_Status value. This value is OK if the reply was unmarshalled successfully. The return of this value does not necessarily mean that the command was completed successfully, only that the reply was unmarshalled. You must also check the M_Status within the reply.

SEElib_FreeCommand

extern int SEElib_FreeCommand(struct M_Command *cmd);

This function frees a command structure and is equivalent to the generic stub function NFastApp_FreeCommand (described in the nCore CodeSafe API Documentation).

SEElib_FreeReply

extern int SEElib_FreeReply(struct M_Reply *reply);

This function frees a reply structure and is equivalent to the generic stub function NFastApp_FreeReply (described in the nCore CodeSafe API Documentation).

SEElib_SetPort

extern void SEElib_SetPort(unsigned short port);

CodeSafe 5 for nShield 5 only: Sets a custom port to bind to for receiving SEEJobs from the host.

By default, port 8888 is used, and that is also the default port used by client-side configuration support. If using the default port, there is no need to call this function. For a custom port to take effect, this must be called before SEElib_init().

To disable listening for SEEJobs altogether, call SEElib_SetPort(0) before SEElib_init().

SEElib_SubmitCoreJob

extern int SEElib_SubmitCoreJob( const unsigned char *data, unsigned int len );

This function puts a job on the input queue for processing by the core. The byte block is passed in data and len. It should be a full marshalled M_Command with a valid tag at the start.

This function returns an M_Status, which is typically OK or BufferFull (if len is too big).

SEElib_GetCoreJob

extern int SEElib_GetCoreJob ( unsigned char *buf, M_Word *len_io );

This function blocks and waits for a job submitted to the core to be returned. On entry, buf points to a buffer of length (*len_io) max. On exit, if successful, *len_io is the length of bytes returned.

This function returns an M_Status, which is typically OK or BufferFull (if len_io is too big).

SEElib_GetUserDataLen

extern M_Word SEElib_GetUserDataLen ( void );

In CodeSafe 5, this function gets the length in bytes of the /etc/userdata.codesafe file in the filesystem of the container.

If this data has been discarded because SEElib_ReleaseUserData() has been called, this function returns 0.

SEElib_Submit

extern int SEElib_Submit(M_Command *cmd, M_Reply *reply, PEVENT ev, SEElib_ContextHandle tctx);

This function submits the command specified in cmd. The transaction listener thread calls EventSet ev, if ev is non-NULL, when the reply returns for this command. The reply is unmarshalled into reply and tctx is returned to the caller in SEElib_Query.

Unlike SEElib_SubmitCoreJob this function can be called at the same time as another thread is blocking in SEElib_Transact.

SEElib_StartTransactListener must have been called before this function is called.

SEElib_Query

extern int SEElib_Query(M_Reply **replyp, SEElib_ContextHandle *tctx_r);

This function is called to receive a reply that is being held by the transaction listener thread. It is typically called after having been woken from EventWait as a result of the transaction listener thread posting to the event passed in to SEElib_Submit.

If *replyp is NULL, SEElib_Query accepts any returned reply, and *replyp is changed to point to that reply. If *replyp is not NULL, the function accepts the reply specified; other replies are queued internally.

tctx_r can be NULL. If it is not, the tctx used when submitting the reply is stored in *tctx_r. SEElib_Query can return, in addition to the usual return values, TransactionNotYetComplete if the reply (or any reply if *replyp was NULL) has not come back from the core yet.

SEElib_StartTransactListener must have been called before this function is called.

SEElib_AwaitJob

extern int SEElib_AwaitJob( M_Word *tag_out, unsigned char *buf, M_Word *len_io );

This function blocks and waits for the next SEEJob to come in from the host-side application. On entry, *buf and *len_io give the base and length of a buffer area to receive the job. On return, *len_io is set to the length delivered (if the job is received successfully). This buffer is a copy of the seeargs field of the SEEJob that was sent by the host-side application.

The *tag_out value is the tag for this command. Each transaction must have a unique tag when sent from the host-side application to ensure transactions are returned to their required caller. The generation of unique tags is handled by the host-side compatibility layer. The tag must be returned in the SEElib_ReturnJob so that the host-side compatibility layer associates the reply with this transaction.

The SEElib_AwaitJob function returns an M_Status, which is OK on success and normally, but not always, BufferFull on failure.

If you use SEElib_StartProcessorThreads(), these function calls are done automatically and you should not call this function yourself.

SEElib_AwaitJobEx

extern void SEElib_AwaitJobEx( M_Word *tag_out, unsigned char *buf, M_Word *len_io, unsigned flags );

Block on the socket waiting for a SEEJob command from the host.

The output parameters are filled with information obtained from the message itself. On entry, *buf and *len_io give the base and length of a buffer area to receive the job. On return, *len_io is set to the length delivered (if the job is received successfully). This buffer is a copy of the seeargs field of the SEEJob command. The *tag_out value is the tag for this command.

SEElib_ReturnJob

extern void SEElib_ReturnJob( M_Word tag, const unsigned char *data, unsigned int len );

This function returns an SEEJob reply to the host-side application. It is sent in a way that the host-side compatibility layer can interpret and write into the corresponding reply struct on the host-side.

If you use the SEElib_StartProcessorThreads() function, it calls SEElib_ReturnJob() for you.

The tag field must match the tag supplied in the SEElib_AwaitJob() call that created the job.

The given data is copied away and forms the seereply field of the SEEJob reply on the host-side application.

SEElib_StartProcessorThreads

struct ProcessThreadCtx; /* User-defined */
typedef struct SEElib_ProcessContext
{
  struct ProcessThreadCtx *uc;

  unsigned char *iobuf;
  int iobuf_maxlen;
}
  SEElib_ProcessContext;

typedef struct ProcessThreadCtx * (*SEEJobInitFn) (SEElib_ProcessContext *pC);

/* Function called during thread initialisation */
typedef int (*SEEJobFn) ( SEElib_ProcessContext *pC, M_Word tag, int in_len );

/* Function to process an SEEJob; data is sent in & out via pC->iobuf.
Returns length being returned.
*/
extern int SEElib_StartProcessorThreads(int nthreads, int stacksize, SEEJobInitFn
pfnInit, SEEJobFn pfnProcess);

This function causes the SEE compatibility layer to start a number of processing threads. Each thread has its own SEElib_ProcessContext allocated, which remains constant throughout the life of the thread.

A working buffer for a given thread is allocated; the iobuf member points to this buffer and iobuf_maxlen is set to the size. Data for the SEEJob is passed in and out through this buffer.

For each thread, the supplied SEEJobInitFn is called first, and the ProcessThreadCtx pointer it returns is stored in the SEElib_ProcessContext structure. This structure is typically a convenient thread-local storage. The pointer may be NULL if it is not required.

When a job arrives for the given thread, the supplied SEEJobFn is called. It is passed the SEElib_ProcessContext pointer pC, a tag, and a length (in_len). The SEEJob data is at pC→iobuf, length in_len. The tag is for information only. The function processes the data and leave a reply at pC→iobuf. The return value from the function indicates the number of bytes to be returned from this buffer.

SEElib_StartSEEJobListener

extern int SEElib_StartSEEJobListener(PEVENT ev);

This function starts the SEEJob listener thread which blocks calling SEElib_AwaitJob, caches the new job and then sets the event ev if ev is non-NULL.

Use SEElib_QuerySEEJob to receive any SEEJobs that have been cached by this listener thread, followed by SEElib_ReturnJob to reply to the SEEJob, then followed by SEElib_ReleaseSEEJob to free the buffer.

It is safe to call this function multiple times, however calls after the first call have no effect.

SEElib_QuerySEEJob

extern M_Status SEElib_QuerySEEJob( M_Word *tag_out, unsigned char **buf, M_Word *len );

This function is called to receive a SEEJob that is being held by the SEEJob listener thread. It is typically called after having been woken from EventWait as a result of the SEEJob listener thread setting the event passed in to SEElib_StartSEEJobListener.

buf is set to the buffer containing the SEEJob, len is set to the length of the data contained in buf.

This function returns TransactionNotYetComplete if there were no outstanding SEEJobs.

SEElib_ReleaseSEEJob

extern void SEElib_ReleaseSEEJob( unsigned char **buf );

This function is called to release a buffer which was returned from SEElib_QuerySEEJob. It must be called after the buffer specified by buf in a call to SEElib_QuerySEEJob has been finished with. This function is safe to call even if *buf is NULL. In addition, it sets *buf to NULL on completion.

Host-side SEEJobs

Host-side applications using SEEJobs can send them as normal nCore commands over a hardserver connection, referencing the SEE World ID of the SEE machine in question. The hardserver will automatically dispatch such commands over the mutually authenticated SSH tunnel to the SEE machine where applicable.

SEEJobs can be sent as M_Command commands with the cmd set as either Cmd_SEEJob (which does not time out, except due to communication failure) and Cmd_FastSEEJob (which times out after 2 minutes if the SEE machine does not reply to that job in that timeframe, in which case the status is set to Status_HardwareFailed, but this is not a fatal error unless the communication as a whole has failed).

Java clients may alternatively use the seeJob() helper method of the PublishedSEEWorld or SEEWorld5 classes.