Updated on 2024-07-19 GMT+08:00

QingTian Enclave Application Development on Linux

QingTian Enclave SDK

The QingTian Enclave SDK consists of a series of open-source libraries for you to develop your own QingTian Enclave applications. It includes the qtsm-lib function library provided by QTSM. In addition, the QingTian Enclave SDK integrates with KMS APIs that provide built-in support for obtaining attestation documents and other KMS-related functions. The typical examples show how to call KMS APIs for decryption in QingTian Enclave.

Table 1 API description

Type

API

Description

libqtsm APIs

qtsm_describe_pcr

Queries the PCR value of a specified index.

qtsm_extend_pcr

Extends the PCR value of a specified index.

qtsm_lock_pcr

Locks the PCR value of a specified index.

qtsm_lock_pcrs

Locks the PCR values of specified indexes in batches.

qtsm_get_describe

Obtains the QTSM information.

qtsm_get_attestation

Obtains the attestation document.

qtsm_get_random

Obtains the hardware random number.

KMS APIs

kms_generate_datakey_blocking

Generates a new key pair and obtains the public key and the private key.

kms_generate_datakey_blocking_with_proxy

Integrates the qtproxy and obtains the key pair.

kms_gen_random_blocking

Obtains a random number.

kms_gen_random_blocking_with_proxy

Integrates the qtproxy and obtains the random number.

kms_decrypt_data_blocking

Decrypts data.

kms_decrypt_data_blocking_with_proxy

Integrates the qtproxy and decrypts data.

You can obtain the source code for free from the open source repository at https://gitee.com/HuaweiCloudDeveloper/huawei-qingtian/tree/master/enclave and develop your own QingTian Enclave application based on the test example.

Vsock Communication

The following uses vsock as an example to describe how to develop QingTian Enclave applications on Linux. The vsock application in this example can only run on Linux instances.

The vsock sample application helps developers know how information is exchanged between the parent instance and the QingTian Enclave instance. The vsock application includes two parameters: Server and Client. You can specify the two parameters to define the roles (client or server application) for the parent instance and the QingTian Enclave instance. In the vsock application, the client application sends a simple text message over the vsock to the server application and the server application listens to the vsock and prints the message to the console once it receives the message.

The following describes how a QingTian Enclave instance functioning as the server application receives the hello world message from the parent instance functioning as the client application.

  1. Compile a SocketCommunication.py program.
    #!/usr/local/env python3
    import argparse
    import socket
    import sys
    
    CID_DEFAULT = 3
    PORT_DEFAULT = 9999
    TIMEOUT = 5
    BLACKLOG_DEFAULT = 5
    
    class Client:
        def __init__(self, cid, port):
            self.clientAddr = (cid, port)
            self.connect()
    
        def connect(self):
            self.socket = socket.socket(socket.AF_VSOCK, socket.SOCK_STREAM)
            self.socket.settimeout(TIMEOUT)
            print("connecting to the server")
            try:
                self.socket.connect(self.clientAddr)
            except socket.error:
                print("client's socket connection err")
                sys.exit(1)
    
        def send(self, msg):
            print("client sends hello to the server")
            self.socket.sendall(msg)
    
        def disconnect(self):
            self.socket.close()
    
        def receiveData(self):
            while True:
                try:
                    message = self.socket.recv().decode()
                except (socket.error, UnicodeDecodeError):
                    break
                if message:
                    print(message, end = " ", flush = True)
            print()
    
    def clientHandler(args):
        client = Client(args.cid, args.port)
        message = "Hello world"
        client.send(message.encode())
        client.disconnect()
    
    class Server:
        def __init__(self, port):
            self.socket = socket.socket(socket.AF_VSOCK, socket.SOCK_STREAM)
            self.serverAddr = (socket.VMADDR_CID_ANY, port)
            self.socket.bind(self.serverAddr)
            self.socket.listen(BLACKLOG_DEFAULT)
    
        def receiveData(self):
            while True:
                print("waiting for a connection")
                (conn, clientAddr) = self.socket.accept()
                try:
                    print("connection from ", clientAddr)
                    while True:
                        try: 
                            data = conn.recv(256).decode()
                        except (socket.error, UnicodeDecodeError):
                            break
                        if data:
                            print("data: ", data)
                        else:
                            print("connection close")
                            break
                finally:
                    conn.close()
    
    def serverHandler(args):
        server = Server(args.port)
        server.receiveData()
    
    
    def main():
        parser = argparse.ArgumentParser(description = "Hello world demo", prog='SocketCommunication')
        subparsers = parser.add_subparsers(description = "Communication roles")
        parserClient = subparsers.add_parser("Client", description = "Client",
                                            help = "Communicate with server using a given cid and port.")
        parserClient.add_argument("-c", "--cid", default = CID_DEFAULT, type = int, help = "Client's Cid")
        parserClient.add_argument("-p", "--port", default = PORT_DEFAULT, type = int, help = "Client's port")
        parserClient.set_defaults(func = clientHandler)
        parserServer = subparsers.add_parser("Server", description = "Server", help = "Listen on a given port")
        parserServer.add_argument("-p", "--port", default = PORT_DEFAULT, type = int, help = "Server's Port")
        parserServer.set_defaults(func = serverHandler)
        if len(sys.argv) < 2:
            parser.print_usage()
            sys.exit(1)
        args = parser.parse_args()
        args.func(args)
    
    
    if __name__ == "__main__":
        main()
  1. Create a file named Dockerfile.
    #start the Docker image from ubuntu
    FROM ubuntu AS base-img
    WORKDIR /home/builder
    # COPY vsocket example
    COPY . vsocket
    # install relative dependencies
    RUN apt-get update && \
        apt-get install python3 -y && \
        apt-get install gcc -y && \
        apt-get install gawk -y
    # Launch a client
    CMD ["python3", "/home/builder/vsocket/SocketCommunication.py","Server","-p 9999"]
  1. Build a Docker image.
    sudo docker build -t vsock-sample-client -f Dockerfile .
  1. Convert the Docker image to a QingTian Enclave image file.
    qt enclave make-img --docker-uri vsock-sample-client --eif vsock_sample.eif
  1. Boot the QingTian Enclave instance in debug mode using the QingTian Enclave image file vsock_sample.eif.
    qt enclave start --cpus 2 --mem 4096 --eif vsock_sample.eif --debug-mode --cid 4
    Run the qt enclave console command to view the read-only terminal output in the QingTian Enclave instance.
    qt enclave console --enclave-id 0
    waiting for a connection
  1. Boot a parent instance terminal and start the client program.
    python3 SocketCommunication.py Client -c 4 -p 9999
  1. When the server application receives the message over the vsock, it prints the message to the console.
    connection from  (3, 4180219645)
    data:  Hello world
    connection close
    waiting for a connection

Example of Using libqtsm and SDKs

The following describes how to use libqtsm and SDK APIs in QingTian Enclave applications based on open-source sample code. The sample application can only run on Linux instances.

  1. Install the libqtsm development package.

    yum install libqtsm-devel

  1. Obtain the open-source sample code from the following URL and copy it to the environment where the QingTian Enclave image is built.

    https://gitee.com/HuaweiCloudDeveloper/huawei-qingtian/tree/master/enclave/qtsm

  1. Create a file named Dockerfile.
    # start the Docker image from ubuntu
    FROM ubuntu AS base-img
    WORKDIR /home/builder
    # COPY libqtsm example
    COPY ./qtsm qtsm_tests/
    # install relative dependencies
    RUN apt-get update && \
        apt-get install gcc -y && \
        apt-get install make -y && \
        apt-get install libssl-dev -y && \
        apt-get install libglib2.0-dev -y && \
        apt-get install curl -y && \
        apt-get install libcurl4-openssl-dev –y  && \
        apt-get install -y libcbor-dev && \
        apt-get install -y libjson-c-dev
    # build a test demo
    RUN cd qtsm_tests/tests/ && \
           make
    RUN cp /home/builder/qtsm_tests/tests/gtest_libqtsm /root/
    # Launch a client
    CMD "/root/gtest_libqtsm"
  1. Build a Docker image, convert it to a QingTian Enclave image file, and boot the QingTian Enclave instance.
  2. Obtain the open-source sample code of SDK APIs from the following URL:

    https://gitee.com/HuaweiCloudDeveloper/huawei-qingtian/tree/master/enclave/qtsm-sdk-c/samples