C Porting Layer API Reference for Oracle Internet of Things Cloud Service Client Software Library. Release 21.1.1.0.0-3. E80003-19
Porting layer overview

The device and enterprise client libraries simplify working with the Oracle IoT Cloud Service. These client libraries are a low-level abstraction over top of messages and REST APIs. Device clients are primarily concerned with sending data and alert messages to the cloud service, and acting upon requests from the cloud service. Enterprise clients are primarily concerned with monitor and control of device endpoints.

The Oracle Internet of Things C Client Library is a high level native library for accessing the Oracle IoT Cloud Service. Basically, Cloud Service supports only low level REST API and this library provides higher level abstraction on top of that making development of client applications easier and faster.

This specification describes API of some functionality that required by Client Library but can't be implemented using C99 language standard. It contains some platform depended functionality like thread, mutexes, cryptography, etc.

C CL Porting Guide Draft

Table of Contents

1.Preface

2.Prerequisites

3.Overview

4.Build time options

Shared options

5.Mandatory Porting API

iotcs_port_system.h:

iotcs_port_queue.h:

iotcs_port_crypto.h:

iotcs_port_ssl.h:

6.Optional Porting API

Dynamic Memory Allocation API

iotcs_port_memory.h:

Optional thread related API

iotcs_port_thread.h:

iotcs_port_mutex.h

Optional diagnostic capability porting API

iotcs_port_diagnostics.h:

Optional for Message Dispatcher

iotcs_port_queue.h:

Optional for Long Polling support

iotcs_port_ssl.h:

Optional for automatic device time adjustment

iotcs_port_system.h:

7. UTAM porting API

Library needs a TAM module that provides trusted_assets_manager.h API. This API gives library access to IoT server URL, endpoint id, endpoint public key and encryption using shared secret and private key.

There is an internal TAM implementation that supports two modes: Default TAM (obsolete and deprecated - kept for compatibility) and Unified TAM (unified format for all client libraries).

iotcs_port_tam.h:

void iotcs_port_tam_init (void);
Initializes porting layer for default TAM.

void iotcs_port_tam_finalize(void);
Clears all the resources allocated so far.

iotcs_result iotcs_port_tam_set_ts_password(const char* trust_store_password);
Save given password for later use.

size_t iotcs_port_tam_secret_hash(IOTCS_TYPE_SHA type, const unsigned char* key, size_t key_length, const unsigned char* content, size_t content_length, unsigned char *hash, size_t hash_maxsize);
Generates secret hash used for authentication and to get access token.

iotcs_result iotcs_port_tam_unified_credentials_decrypt(unsigned char *out, size_t* out_len, const unsigned char* in, size_t in_len, const unsigned char* iv);
Decrypts the data from unified trusted assets store. Function uses password given with iotcs_port_tam_set_ts_password call. Expands the password into 16 bytes using PKCS#5 PBKDF2 SHA1 HMAC with 10000 iterations. And finally decrypt the data with 128 bit AES Cipher Block Chaining (CBC) and PKCS#5 padding. iv argument is used as initialization vector in decryption process.

iotcs_result iotcs_port_tam_unified_credentials_encrypt(unsigned char *out, size_t* out_len, const unsigned char* in, size_t in_len, const unsigned char* iv);
Similar to iotcs_port_tam_unified_credentials_decrypt but does inverse transformation.

size_t iotcs_port_tam_get_trust_anchors_count(void);
Get number of trusted certificates

const char* iotcs_port_crypto_get_trust_anchor_certificate(size_t index, size_t *len);
Get certificate in index position in DER format.

iotcs_result iotcs_port_crypto_serialize_private_key(unsigned char *buf, size_t buf_length, size_t *written);
Serialize private key in PKCS#8 format into given buffer.

iotcs_result iotcs_port_crypto_deserialize_private_key(unsigned char *buf, size_t buf_length);
Load private key (and public) in PKCS#8 format from given buffer.

iotcs_result iotcs_port_ tam_generate_keypair(size_t key_size, unsigned char* public_out, size_t* public_length);
Generates RSA key pair and return public key in DER format.

size_t iotcs_port_tam_sign_with_private_key(IOTCS_TYPE_SHA type, const unsigned char* input, size_t input_length, char* signature, size_t signature_maxsize);
Sign given input with generated private key (in call
iotcs_port_tam_generate_keypair) or loaded private key (in call iotcs_port_crypto_deserialize_private_key).

Default TAM support methods (Obsolete and Deprecated)

There is no need to implement these methods as long as no Default TAM support is required.

iotcs_port_tam.h:

iotcs_result iotcs_port_tam_decode_shared_secret(char* encrypted_shared_secret, char *shared_secret, int shared_secret_length);
iotcs_result iotcs_port_tam_check_file_signature(const char* file, size_t signed_data_length, const char* signature);
iotcs_result iotcs_port_tam_load_trust_store(const char* trust_store_path);
iotcs_result iotcs_port_tam_load_trust_store_achors(const unsigned char* trust_store_anchors, int length);

iotcs_result iotcs_port_tam_credentials_load(const char *client_id, char *endpoint_id, size_t *endpoint_length, unsigned char *public_key, size_t *public_key_len);
iotcs_result iotcs_port_tam_credentials_store(void);

8. Custom TAM

If Unified TAM doesn’t meet security requirements or target device doesn’t have local file system or for some other reason user could use his own Custom TAM implementation instead of UTAM. Custom TAM must provide TAM API to C CL library. TAM API that could be found in source bundle in file ./iotcs/csl/posix/src/shared/trusted_assets_manager/iotcs_tam.h (path for posix release). UTAM implementation could be used as an example (could be found in source bundle in file ./iotcs/csl/posix/src/shared/trusted_assets_manager/iotcs_tam.c - path for posix release).

9. Examples of porting

There are existing ports that could serve as a good example. Probably the most demonstrative port example is the Posix port. This port uses:

  • OpenSSL library for cryptography and SSL

  • pthread library for thread API, mutex API, queue API implementation.

  • The rest functionality is implemented using: POSIX standard IEEE Std 1003.1with XSI Extension. E.g. <sys/time.h>, <sys/types.h>, <sys/socket.h>, <sys/utsname.h>, <sys/statvfs.h>, <net/if.h>, <arpa/inet.h>, <netinet/in.h>.

Another good example of porting, but this time to embedded system, is port to frdm-k64f board which is called “Mbed” port. Embedded systems tends to be a resource constrained devices with limited amount of memory and CPU power and this fact has an impact on implementation. This port uses:

  • MbedTLS library for cryptography and SSL

  • And Mbed RTOS for the rest: thread API, mutex API, queue API implementation and etc.

10. Build system adjustment

For building the library on a new platform probably it is worth to reuse existing build system. This section will describe required steps to do so.

Please note that all the instructions is this guide are for posix release, for other releases please substitute “posix” directory with the release platform name. Also this guide might not include all needed steps.

How to add custom porting layer

This is the instruction how to build the library with an implementation for a new porting layer.

  1. Open iotcs/csl/posix/make/config/paths.cfg

  2. Set the path to directory with port sources (<custom_port_src>) as a PORT_SRC_DIR variable value

  3. Create your implementation for iotcs/csl/posix/src/include/port/iotcs_port_XXX.h API in < custom_port_src >/<custom_port_XXX.c> files. iotcs_port_tam.h could be not implemented.

  4. Copy iotcs/csl/posix/src/include/port/iotcs_port_tam.h into <custom_port_src> folder. This needed to minimize changes in build system.



Otherwise you should change /csl/posix/make/posix/impl.mk at line 13 that contained target to compile port TAM sources like:

# Compile port TAM source files into .o files

$(PORT_TAM_OBJ_DIR)/%.o: $(SRC_DIR)/$(PORT)/%.c

$(A)mkdir -p $(dir $@)

$(A)$(CC) $(CPPFLAGS) $(CPP_OPTS) $(CFLAGS) $(C_OPTS) $(PORT_FLAGS) $(PORT_OPTS) $(TAM_FLAGS) $(TAM_OPTS) $(OBJECT_FILE_NAME_OPT)$@ $<

And add include in CPPINCLUDES variable in iotcs/csl/posix/make/common.mk at line 115:

CPPINCLUDES=-I$(PORT_INC_DIR) -I$(INC_DIR) -I$(SHARED_DIR) -I$(OUT_LIB_PATH)

-I$(SRC_DIR)/$(PORT)

  1. (optional) Add target to compile c++ files in file/csl/posix/make/posix/impl.mk:

    $(PORT_OBJ_DIR)/%.o: $(PORT_SRC_DIR)/%.cpp

    $(A)mkdir -p $(dir $@)

    $(A)$(CC) $(CPPFLAGS) $(CPP_OPTS) $(CXXFLAGS) $(CXX_OPTS) $(PORT_FLAGS) $(PORT_OPTS) $(OBJECT_FILE_NAME_OPT)$@ $<

  2. Build library

After these changes you could build library as usual, but library will have custom porting layer in it. In addition, you can build library with only porting layer.

Generate library with only porting layer:

make .library_porting_impl

How to add new compiler

If target platform’s compiler is not GCC then in order to support new compiler in the build system it is required to follow these steps:

  1. Go to /iotcs/csl/posix/make/cc

  2. Copy gcc.cfg to <compiler>.cfg

  3. (optional) Set default values for custom arguments. For example,

    TOOLS_PREFIX?=/<compiler_path>/bin

    OUT_CC_SUBDIR?=<compiler>

  4. Set internal variables

    CC=$(TOOLS_PREFIX)<compiler>

    CXX=$(TOOLS_PREFIX)<compiler for c++>

    AS=$(TOOLS_PREFIX) <compiler for assembler files>

    LD=$(TOOLS_PREFIX) <linker>

    AR=$(TOOLS_PREFIX)< archiver>

    OBJCPY=$(TOOLS_PREFIX) <object copy tool>

  5. Go to /iotcs/csl/posix/make and execute next command:

make CC_CFG=<compiler>

How to add custom TAM

Custom TAM:

  1. Create your implementation for iotcs/csl/posix/src/shared/trusted_assets_manager/iotcs_tam.h API in file < custom_tam _path>/<custom_tam.c>

  2. Open iotcs/csl/posix/make/common.mk at line 313 that contained target to compile TAM sources

    # targets for compile TAM sources

    $(TAM_OBJ_DIR)/%.o: $(SHARED_DIR)/%.c

    $(A)mkdir -p $(dir $@)

    $(A)$(CC) $(CPPFLAGS) $(CPP_OPTS) $(CFLAGS) $(C_OPTS) $(TAM_FLAGS) $(TAM_OPTS) $(OBJECT_FILE_NAME_OPT)$@ $<

  3. Change this target:

# targets for compile TAM sources

$(TAM_OBJ_DIR)/%.o: < custom_tam _path>/<custom_tam.c>

$(A)mkdir -p $(dir $@)

$(A)$(CC) $(CPPFLAGS) $(CPP_OPTS) $(CFLAGS) $(C_OPTS) $(TAM_FLAGS) $(TAM_OPTS) $(OBJECT_FILE_NAME_OPT)$@ $<

< custom_tam _path> must be either an absolute path or a path relative to the iotcs/csl/posix folder ($(PROJ_DIR) variable)

Custom port TAM:

If required it is possible to support porting layer for a custom TAM.

  1. Create your implementation for iotcs/csl/posix/src/include/port/iotcs_port_tam.h API in file < custom_port_tam _path >/<custom_port_tam.c>

  2. Open iotcs/csl/posix/make/posix/impl.mk at line 13 that contained target to compile port TAM sources

    # Compile port TAM source files into .o files

    $(PORT_TAM_OBJ_DIR)/%.o: $(PORT_SRC_DIR)/%.c

    $(A)mkdir -p $(dir $@)

    $(A)$(CC) $(CPPFLAGS) $(CPP_OPTS) $(CFLAGS) $(C_OPTS) $(PORT_FLAGS) $(PORT_OPTS) $(TAM_FLAGS) $(TAM_OPTS) $(OBJECT_FILE_NAME_OPT)$@ $<

  3. Change this target:

# Compile port TAM source files into .o files

$(PORT_TAM_OBJ_DIR)/%.o: < custom_port_tam _path >/<custom_port_tam.c>

$(A)mkdir -p $(dir $@)

$(A)$(CC) $(CPPFLAGS) $(CPP_OPTS) $(CFLAGS) $(C_OPTS) $(PORT_FLAGS) $(PORT_OPTS) $(TAM_FLAGS) $(TAM_OPTS) $(OBJECT_FILE_NAME_OPT)$@ $<

< custom_port_tam _path > must be either an absolute path or a path relative to the iotcs/csl/posix folder ($(PROJ_DIR) variable)

After these changes you could build library as usual, but library will have custom TAM in it. In addition, you can build only TAM library.

Generate only TAM library:

make .tam_library_impl