SEE API documentation
SEElib
is an API that enables an SEE machine to execute nCore API commands.
Historically, the SEElib
also provided the functionality which connected SEE machines to their host-side applications via the nCore API.
In CodeSafe 5, SEElib
still provides the methods necessary to execute nCore API commands, but communication between the SEE machine and the host-side application is expected to be done using TCP/IPv6 network connections which are managed directly by the SEE machine.
To allow for a more seamless integration of legacy SEE machines, which previously transacted with their host-side application via the nCore API, a compatibility layer has been created to automatically manage these legacy transactions.
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.
|
Why CodeSafe 5 needs a compatibility layer
The compatibility layer allows pre-existing CodeSafe users to port legacy SEE machines that were developed for nShield XC or Solo+ HSMs to the CodeSafe 5 environment.
CodeSafe 5 has a Launcher service for managing the SEE container, instead of using nCore API commands. All requests related to container (SEE machine) management, for example to load a new SEE machine onto the HSM or to start, stop, or destroy a SEE machine, are made directly to the new Launcher service.
Legacy SEElib
applications previously allocated memory by the Cmd_CreateSEEWorld
nCore API command.
In CodeSafe 5, launcher receive
, launcher create
, and launcher start
requests are made to the Launcher service in combination with a new Cmd_CreateSeeConnection
command to the nCore API service to get a SEE machine running and able to communicate with the nCore API service.
For CodeSafe 5 applications, the nCore API service does not support the Cmd_SEEJob
nCore API command.
Instead, the command is requested directly from the client application on the host to the SEE machine using a direct TCP/IPv6 network connection.
The compatibility layer provides support for this new connection method.
CodeSafe 5 does not use the concept of UserData
.
A developer can include any files, using any directory structure, in the container image that is installed in the HSM.
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.
UserData
in CodeSafe 5 is a file located inside the container (/etc/codesafe.userdata
) and must be added when the image is constructed.
SEElib_ReleaseUserData
extern void SEElib_ReleaseUserData(void);
In CodeSafe 5 this function does not do anything. It is only present to satisfy the linker.
SEElib_InitComplete
extern void SEElib_InitComplete( M_Word status );
In CodeSafe 5 this function does not do anything. It is only present to satisfy the linker.
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_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.
About the SEElib compatibility layer
The compatibility layer is provided to help port existing SEE machines and their host-side applications to the new CodeSafe 5 architecture.
The compatibility layer provides support for legacy methods that dealt with the host-side application/SEE machine connection (sending SEEJobs between the two and their supporting methods).
Because the new CodeSafe 5 architecture has removed the need to send SEEJobs between the host-side application and the SEE machine by using the nCore API as an intermediary, these methods are no longer found in the CodeSafe 5 SEElib
API.
For detailed examples of the SEElib compatibility layer’s use, refer to the provided "CSEE" or "Classic SEE" examples. These examples are legacy SEE machine examples that have been ported using the compatibility layer.
SEE machine module side compatibility layer
The module-side compatibility layer provides a small API to emulate the deprecated CSEE methods while using the CodeSafe 5 architecture and TCP/IPv6 network connections underneath.
To continue to use legacy methods within an SEE machine, the SEE machine must be recompiled with the compatibility layer library: liblegacy_compatibility.a
.
The default install location is /opt/nfast/c/csd5/lib-ppc64-linux-musl/liblegacy_compatibility.a
on Linux.
This library provides support for the legacy SEElib methods described below.
There is only a one-line change that needs to be made within an SEE machine’s source to initialize the compatibility layer.
A call to SEElib_Legacy_Support_Init()
.
This call must be made before any of the legacy SEElib
calls are made, typically in main()
after SEElib_init()
.
After this call is made, all legacy methods operate functionally identically to legacy versions of CodeSafe, while using TCP/IPv6 network connections behind the scenes.
Do not write new applications using the compatibility layer. The compatibility layer is provided to simplify the porting of existing legacy applications to CodeSafe 5. |
CodeSafe 5 allows the use of TCP/IPv6 network connections to connect the host-side application to an SEE machine, simplifying the communication between the two, and expanding the functionality of the communication between the two. The compatibility layer allows legacy applications to run using the old style of SEEJobs, but doing so with new applications is not advised.
SEElib_Legacy_Support_Init
This function is provided by the compatibility layer to ease porting applications from Solo XC to nShield 5. Do not use it for new applications. |
extern void SEElib_Legacy_Support_Init(const char* PORT);
This function initializes the compatibility layer for legacy SEE machines for use with CodeSafe 5. This method must be called before any other legacy methods. This method initializes all the support required for legacy SEE machines to function properly.
SEElib_AwaitJob
This function is provided by the compatibility layer to ease porting applications from Solo XC to nShield 5. Do not use it for new applications. |
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
This function is provided by the compatibility layer to ease porting applications from Solo XC to nShield 5. Do not use it for new applications. |
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
This function is provided by the compatibility layer to ease porting applications from Solo XC to nShield 5. Do not use it for new applications. |
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
This function is provided by the compatibility layer to ease porting applications from Solo XC to nShield 5. Do not use it for new applications. |
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
This function is provided by the compatibility layer to ease porting applications from Solo XC to nShield 5. Do not use it for new applications. |
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
This function is provided by the compatibility layer to ease porting applications from Solo XC to nShield 5. Do not use it for new applications. |
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.
Compatibility layer API Host side
Legacy host-side applications need to be modified to use the network interface to talk the SEE machine instead of the nCore API.
The bulk of this work is handled automatically by including the host-side compatibility layer and recompiling.
However, all calls to the nCore API which use CMD_SEEJob
need to be modified slightly to reference the new CodeSafe 5 compatible methods.
The compatibility layer provides support to emulate the use cases of the Cmd_SEEJob
message interface.
The compatible calls and the methods they replace are described below.
All other calls by the host-side application to the nCore API will remain unchanged.
netsee_initialize_legacy_seejob_support
This function is provided by the compatibility layer to ease porting applications from Solo XC to nShield 5. Do not use it for new applications. |
extern int netsee_initialize_legacy_seejob_support(const char * cseeContainerMachineIPv6, const char * cseeContainerMachinePort);
This function initializes host-side application compatibility layer to support legacy CodeSafe SEEJob commands.
netsee_initialize_legacy_seejob_support()
must be called to initialize legacy support for CodeSafe 5.
The call creates all necessary processor threads, initializes all values and fields required to process SEEJob M_Commands
, and creates a connection to the SEE machine via TCP/IPv6 networking.
This call must be made before any of the other methods described below are called.
netsee_submit_legacy_seejob
This function is provided by the compatibility layer to ease porting applications from Solo XC to nShield 5. Do not use it for new applications. |
extern int netsee_submit_legacy_seejob(const M_Command *cmd, M_Reply *reply, struct NFast_Transaction_Context *tctx);
This function transmits a SEEJob
command to the SEE application.
Replaces NFastApp_Submit()
.
The compatibility layer strips the relevant SEEJob
information from the M_Command
, issues a unique tag, and marshals this information to a form the compatibility layer compiled SEE machine understands.
It then sends the command to the module directly via a TCP/IPv6 connection initialized by the compatibility layer.
netsee_wait_legacy_seejob
This function is provided by the compatibility layer to ease porting applications from Solo XC to nShield 5. Do not use it for new applications. |
extern int netsee_wait_legacy_seejob(M_Reply **replyp, struct NFast_Transaction_Context **tctx);
This function waits to receive a reply from the SEE machine.
Replaces NFastApp_Wait()
.
The compatibility layer reads an incoming reply from the module, parses the information, and writes it to the correct M_Reply
corresponding to the tag the command was sent with.
It does not proceed beyond the call until this reply has been processed.
After a reply is received and marshaled by the compatibility layer, netsee_wait_legacy_seejob()
will return with the correct reply.
netsee_transact_legacy_seejob
This function is provided by the compatibility layer to ease porting applications from Solo XC to nShield 5. Do not use it for new applications. |
extern int netsee_transact_legacy_seejob(const M_Command *command, M_Reply *reply, struct NFast_Transaction_Context *tctx);
This function transacts a SEEJob
command and waits until a reply is received and written to *reply
.
Replaces NFastApp_Transact()
.
The compatibility layer strips the relevant SEEJob
information from the M_Command
, issues a unique tag, and marshals this information to a form the compatibility layer compiled SEE machine understands.
It then sends the command to the module SEE machine directly via a TCP/IPv6 connection initialized by the compatibility layer.
After sending the command, it waits for a reply from the SEE machine via the established network connection.
The compatibility layer reads the incoming reply from the module, parses the information, and writes it to the correct M_Reply
corresponding to the tag the command was sent with.
After a reply is received and marshaled by the compatibility layer, netsee_transact_legacy_seejob()
returns with the correct M_Reply
having been written to *reply
.
netsee_simple_transact_legacy_seejob
This function is provided by the compatibility layer to ease porting applications from Solo XC to nShield 5. Do not use it for new applications. |
extern int netsee_simple_transact_legacy_seejob(const M_Command *cmd, M_Reply *reply, int fatal);
Transact a SEEJob
command and wait until a reply is received and written to *reply
.
If fatal
is true, and an error occurs, exit(4)
.
Replaces simple_transact()
.
The compatibility layer strips the relevant SEEJob
information from the M_Command
, issues a unique tag, and marshals this information to a form the compatibility layer compiled SEE machine will understand.
It then sends the command to the module SEE machine directly via a TCP/IPv6 connection initialized by the compatibility layer.
Then, it waits for a reply from the SEE machine via the established network connection.
The compatibility layer reads the incoming reply from the module, parses the information, and writes it to the correct M_Reply
corresponding to the tag the command was sent with.
Once a reply is received and marshaled by the compatibility layer, netsee_simple_transact_legacy_seejob()
will return with the correct M_Reply
having been written to *reply
.