PARSEC: Client & Interface
PARSEC, the Platform AbstRaction for SECurity, is an open-source initiative to provide a common API to hardware security and cryptographic services in a platform-agnostic way.
PARSEC is a Cloud Native Compute Foundation Sandbox project, hosted on Github.
In this article I will introduce the client libraries and the interface between the client and the service.
This article is (will be) among a series that cover following aspects of PARSEC:
- PARSEC Introduction
- PARSEC Architecture
- PARSEC Client & Interface (this one)
- PARSEC Server
- PARSEC Provider: Mbed TLS
- PARSEC Provider: TPM
- PARSEC Provider: Trusted Services
- PARSEC Deployment
Overview
PARSEC is designed to work in the Client-Server mode:
- The client end sends Request messages to the server end for service
- The server provides service and then replies Response messages to the client
- The format of the messages is defined with Protocol Buffers
- The messages are transported in a Wire Protocol defined by PARSEC
- The client and the service communicates via the UNIX socket
Next I will go through the implementation of these content. I will not talk about Protocol Buffers. That is out of the scope of this post. Please refer to its document if needed. And I will not talk about the client library for Java and Go because I am not familiar with those 2 languages.
Interface
You can understand the communication interface between the PARSEC server and its client in 3 layers, from top to bottom: Protocol Buffers, Wire Protocol and the socket.
Protocol Buffers
Using Google’s Protocol Buffers, PARSEC defines the logic of the messages between its server and client.
parsec-operations
The language neutral operations are defined as .proto
files for Protocol Buffers. They are stored in the repository https://github.com/parallaxsecond/parsec-operations.
This repository is kind of the center of the interface, because the server and all the client libraries need to integrate it and talk in the agreed protocols.
Wire Protocol
PARSEC defines its messages transport format with Wire Protocol, it is described in the official document.
Header
Each message, Request or Response, has a fixed common header. The layout of the head is like:
The meaning of each field of the header is skipped here, please follow this link for detail.
Requests
The layout of a Request message:
After the header comes the message body, which is the serialized Protocol Buffers content.
Responses
The layout of a Response message:
parsec-interface-rs
A separate repository is defined to handle the Wire Protocol: parsec-interface-rs. It is written in Rust language, is integrated by the server and the Rust client crate.
parsec-interface-rs
is a consumer of parsec-operations
. In the git repository of parsec-interface-rs
, a submodule of parsec-operations
is contained. In the building script, Rust code of manipulating the Protocol Buffers is generated by leveraging the prost
crate. (prost is a Protocol Buffers implementation for the Rust Language. It generates Rust code from proto2
and proto3
files.)
Socket
PARSEC client and server exchange the Request and Response messages via the UNIX socket.
By default, the socket file is /run/parsec/parsec.sock
, you can also change it with the socket_path
option in configuration file.
Rust Client
To write a client program, the developers don’t have to invoke the Rust APIs exported from parsec-interface-rs
to handle the Protocol Buffers logic. PARSEC provides client libraries that have wrapped friendly APIs in commonly used language.
For Rust language, the client crate is parsec-client-rust
.
parsec-client-rust
parsec-client-rust
is a separate repository in the PARSEC project. It is published on crate.io as parsec-client
.
The core of the crate is the struct BasicClient
. The struct provides various API for cryptographic operations.
parsec-tool
A client program consumes the client library. In the case of Rust language, the library is the parsec-client
crate. The client program implements the concrete logics to use the cryptographic functionalities.
PARSEC provides a command line tool parsec-tool
. It is written in Rust, it is built upon the parsec-client
crate.
The parsec-tool
supports some basic cryptographic (and other) operations with its subcommands:
SUBCOMMANDS:
create-csr Create a Certificate Signing Request (CSR) from a keypair
create-ecc-key Create a ECC key pair (curve secp256r1). Used by default for asymmetric signing with
ECDSA (SHA-256)
create-rsa-key Create a RSA key pair (2048 bits). Used by default for asymmetric encryption with RSA
PKCS#1 v1.5
decrypt Decrypt data using the algorithm of the key
delete-client Delete all data a client has in the service (admin operation)
delete-key Delete a key
encrypt Encrypt data using the algorithm of the key
export-public-key Export the public part of the key pair in PEM format
generate-random Generate a sequence of random bytes
help Prints this message or the help of the given subcommand(s)
list-authenticators List the available authenticators supported by the Parsec service
list-clients Lists all clients currently having data in the service (admin operation)
list-keys List all keys belonging to the application
list-opcodes List the supported opcodes for a given provider
list-providers List the available providers supported by the Parsec service
ping Ping the Parsec service and prints the wire protocol version
sign Sign data using the algorithm of the key (base64 signature)
C Client
PARSEC provides a client library for C language as well. The name of the library is Parsec Secure Element Driver
, the repository is parsec-se-driver.
The parsec-se-driver
is not independent. It has to work with Mbed TLS, the reference implementation of PSA Cryptography API. The parsec-se-driver
doesn’t provide any API to the application directly. The API is provided by Mbed TLS, while the parsec-se-driver
is registered as a driver of Mbed TLS that provides the implementation of some specified cryptographical operations.
The structure of the C PARSEC client is illustrated with the following diagram.
With the parsec-se-driver
, a client cryptographic operation performs in these steps:
- The application logic (the Application block in the diagram) calls the PSA Crypto API implemented by the Mbed TLS.
- Mbed TLS distinguish the APIs in call. By default, most of the APIs are served by the software implementation of Mbed TLS. But following APIs will be handled by the
parsec-se-driver
:
* psa_generate_key
* psa_export_public_key
* psa_import_key
* psa_destroy_key
* psa_sign_hash
* psa_verify_hash - The
parsec-se-driver
communicates to the PARSEC server via the interface. - The cryptographic operation is finally served by the PARSEC server and its backend.
Build C Client
The CI of parsec-se-driver
is a good demo to show how a C client should be built.
Assuming you have a single C source file main.c
that consumes the PSA Cryto API. In the source file you should include at least these 2 header files:
/* PSA Crypto API standart header file, provided by Mbed TLS*/
#include "psa/crypto.h"
/* parsec-se-driver header file */
#include "parsec_se_driver.h"
To compile the source code:
gcc -Wall -c -I../../include -I$(MBED_TLS_PATH)/include main.c
To link the program:
gcc -Wall -o test-app main.o -L$(MBED_TLS_PATH)/library -L../../target/release -l:libparsec_se_driver.a -lmbedcrypto -lm -pthread -ldl
Looking into the linking command:
libparsec_se_driver.a
is the product ofparsec-se-driver
after playingcargo build
. It contains the implementation of somepsa_*
functions.libmbedcrypto.so
has to be linked as well, obviously. Seemingly Mbed TLS has the ability to replace its own software implementation of some cryptographic APIs with a library that implements the same APIs. And surprisingly this is done simply when another library is involved during the linkage . I don’t know how this happens.
Go Client
Skipped.
Java Client
Skipped.