Skip to content

Commit

Permalink
[ate] Add DeriveSymmetricKeys call.
Browse files Browse the repository at this point in the history
This change adds the following functions to the ate_api.h library:

1. `AllocateDeriveSymmetricKeyResponse`: Allocates memory for a
   `DeriveSymmetricKeyResponse` call.
2. `FreeDeriveSymmetricKeyResponse`: Releases the memory allocated by
   `AllocateDeriveSymmetricKeyResponse`. This function must be called
    after the caller is done processing the data.
3. `DeriveSymmetricKeys`: Calls the provisioning appliance backend to
   request symmetric keys. The function performs the conversion from C++
   C data structures.

The `ate_dll` implementation uses C data structures to be able to be
integrated with older compilers with limited C++ support.

Signed-off-by: Miguel Osorio <[email protected]>
  • Loading branch information
moidx committed Feb 19, 2025
1 parent b7b2d5a commit 8fc4c5f
Show file tree
Hide file tree
Showing 5 changed files with 372 additions and 53 deletions.
217 changes: 164 additions & 53 deletions src/ate/ate_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,138 @@ extern "C" {
#endif // _WIN32
#endif // DLLEXPORT

#define SKU_SPECIFIC_SIZE 128
enum {
kSkuSpecificSize = 128,
kSymmetricKeyMaxSize = 32,
};

/**
* ate_client_ptr is an opaque pointer to an AteClient instance.
*/
typedef struct {
} * ate_client_ptr;

typedef struct {
// Endpoint address in IP or DNS format including port number. For example:
// "localhost:5000".
const char* pa_socket;

// File containing the Client certificate in PEM format. Required when
// `enable_mtls` set to true.
const char* pem_cert_chain;

// File containing the Client secret key in PEM format. Required when
// `enable_mtls` set to true.
const char* pem_private_key;

// File containing the Server root certificates in PEM format. Required when
// `enable_mtls` set to true.
const char* pem_root_certs;

// SKU authentication tokens. These tokens are considered secrets and are
// used to perform authentication at the client gRPC call level.
const char* sku_tokens;

// Set to true to enable mTLS connection. When set to false, the connection
// is established with insecure credentials.
bool enable_mtls;
} client_options_t;

/**
* The device_id_t is a struct of data passed from secigen to ATE.
* keep fields 4-bytes aligned.
*/
#pragma pack(push, 1)
typedef struct HardwareOrigin {
uint16_t silicon_creator_id;
uint16_t product_id;
uint64_t device_identification_number;
} hardware_origin_t;

typedef struct DeviceId {
hardware_origin_t hardware_origin;
uint8_t sku_specific[kSkuSpecificSize];
uint32_t crc32;
} device_id_t;
#pragma pack(pop)

/**
* Symmetric key seed type. The seed is provisioned by the manufacturer.
*/
typedef enum symmetric_key_seed {
/** Low security seed. This seed is rotated infrequently. */
kSymmetricKeySeedSecurityLow = 1,
/** High security seed. This seed is rotated frequently. */
kSymmetricKeySeedSecurityHigh = 2,
} symmetric_key_seed_t;

/**
* Symmetric key type.
*/
typedef enum symmetric_key_type {
/** Raw plaintext key. */
kSymmetricKeyTypeRaw = 1,
/** cSHAKE128 with the "LC_CTRL" customization string. */
kSymmetricKeyTypHashedLcToken = 2,
} symmetric_key_type_t;

/**
* Symmetric key size.
*/
typedef enum symmmetric_key_size {
/** 128bit key size. */
kSymmetricKeySize128 = 16,
/** 256bit key size. */
kSymmetricKeySize256 = 32,
} symmetric_key_size_t;

/**
* Derive symmetric key parameters.
*/
typedef struct derive_symmetric_key_params {
/** Symmetric key seed. */
symmetric_key_seed_t seed;
/** Symmetric key type. */
symmetric_key_type_t type;
/** Symmetric key size. */
symmetric_key_size_t size;
/** Symmetric key diversifier to use in KDF operation. */
uint8_t diversifier[32];
} derive_symmetric_key_params_t;

/**
* Derive symmetric key request.
*/
typedef struct derive_symmetric_key_request {
/** SKU identifier. */
const char* sku;
/**
* Number of keys requested. Equivalent to the size of the `params` array.
*/
size_t params_count;
/** Derive symmetric key parameters. */
derive_symmetric_key_params_t* params;
} derive_symmetric_key_request_t;

/**
* Symmetric key.
*/
typedef struct symmetric_key {
/** Key size in bytes. */
size_t size;
/** Key data. */
uint8_t key[kSymmetricKeyMaxSize];
} symmetric_key_t;

/**
* Derive symmetric key response.
*/
typedef struct derive_symmetric_key_response {
/** Number of symmetric keys. */
size_t symmetric_key_count;
/** Symmetric keys. */
symmetric_key_t* symmetric_keys;
} derive_symmetric_key_response_t;

/**
* blobType is tag indicating the blob content.
Expand Down Expand Up @@ -82,55 +213,6 @@ typedef struct Blob {
uint8_t value[1];
} blob_t;

/**
* ate_client_ptr is an opaque pointer to an AteClient instance.
*/
typedef struct {
} * ate_client_ptr;

typedef struct {
// Endpoint address in IP or DNS format including port number. For example:
// "localhost:5000".
const char* pa_socket;

// File containing the Client certificate in PEM format. Required when
// `enable_mtls` set to true.
const char* pem_cert_chain;

// File containing the Client secret key in PEM format. Required when
// `enable_mtls` set to true.
const char* pem_private_key;

// File containing the Server root certificates in PEM format. Required when
// `enable_mtls` set to true.
const char* pem_root_certs;

// SKU authentication tokens. These tokens are considered secrets and are
// used to perform authentication at the client gRPC call level.
const char* sku_tokens;

// Set to true to enable mTLS connection. When set to false, the connection
// is established with insecure credentials.
bool enable_mtls;
} client_options_t;

/**
* The device_id_t is a struct of data passed from secigen to ATE.
* keep fields 4-bytes aligned.
*/
#pragma pack(push, 1)
typedef struct HardwareOrigin {
uint16_t silicon_creator_id;
uint16_t product_id;
uint64_t device_identification_number;
} hardware_origin_t;

typedef struct DeviceId {
hardware_origin_t hardware_origin;
uint8_t sku_specific[SKU_SPECIFIC_SIZE];
uint32_t crc32;
} device_id_t;
#pragma pack(pop)
/**
* Creates an AteClient instance.
*
Expand Down Expand Up @@ -183,11 +265,40 @@ DLLEXPORT int CreateKeyAndCertificate(ate_client_ptr client, const char* sku,
const size_t serial_number_size);

/**
* Registers an OpenTitan device record.
* Allocates a `derive_symmetric_key_request_t` structure.
*
* The allocated structure should be freed using
* `FreeDeriveSymmetricKeyRequest`.
*
* @param key_count The number of keys to allocate space for.
* @return The allocated structure. Returns NULL on failure.
*/
DLLEXPORT derive_symmetric_key_response_t* AllocateDeriveSymmetricKeyResponse(
size_t key_count);

/**
* Frees a `derive_symmetric_key_response_t` structure.
*
* @param response The structure to free.
*/
DLLEXPORT void FreeDeriveSymmetricKeyResponse(
derive_symmetric_key_response_t* response);

/**
* Derive symmetric keys.
*
* The function derives symmetric keys based on the request parameters.
* Allocate a `derive_symmetric_key_response_t` structure to store the response
* by calling `AllocateDeriveSymmetricKeyResponse`.
*
* TODO(#16): implement device registration function.
* @param client A client instance.
* @param request The request parameters.
* @param response The response parameters.
* @return The result of the operation.
*/
// DLLEXPORT int RegisterDevice(...);
DLLEXPORT int DeriveSymmetricKeys(ate_client_ptr client,
const derive_symmetric_key_request_t* request,
derive_symmetric_key_response_t* response);

#ifdef __cplusplus
}
Expand Down
31 changes: 31 additions & 0 deletions src/ate/ate_client.cc
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

#include "absl/log/log.h"
#include "absl/memory/memory.h"
#include "absl/status/statusor.h"
#include "src/pa/proto/pa.grpc.pb.h"
#include "src/transport/service_credentials.h"

Expand All @@ -26,6 +27,10 @@ using pa::CloseSessionRequest;
using pa::CloseSessionResponse;
using pa::CreateKeyAndCertRequest;
using pa::CreateKeyAndCertResponse;
using pa::DeriveSymmetricKeysRequest;
using pa::DeriveSymmetricKeysResponse;
using pa::EndorseCertsRequest;
using pa::EndorseCertsResponse;
using pa::InitSessionRequest;
using pa::InitSessionResponse;
using pa::ProvisioningApplianceService;
Expand Down Expand Up @@ -130,6 +135,32 @@ Status AteClient::CreateKeyAndCert(const std::string& sku,
return stub_->CreateKeyAndCert(&context, request, reply);
}

Status AteClient::EndorseCerts(EndorseCertsRequest& request,
EndorseCertsResponse* reply) {
LOG(INFO) << "AteClient::EndorseCerts";

// Context for the client (It could be used to convey extra information to
// the server and/or tweak certain RPC behaviors).
ClientContext context;
context.AddMetadata("authorization", sku_session_token_);

// The actual RPC - call the server's EndorseCerts method.
return stub_->EndorseCerts(&context, request, reply);
}

Status AteClient::DeriveSymmetricKeys(DeriveSymmetricKeysRequest& request,
DeriveSymmetricKeysResponse* reply) {
LOG(INFO) << "AteClient::DeriveSymmetricKeys";

// Context for the client (It could be used to convey extra information to
// the server and/or tweak certain RPC behaviors).
ClientContext context;
context.AddMetadata("authorization", sku_session_token_);

// The actual RPC - call the server's DeriveSymmetricKeys method.
return stub_->DeriveSymmetricKeys(&context, request, reply);
}

Status AteClient::RegisterDevice(RegistrationRequest& request,
RegistrationResponse* reply) {
LOG(INFO) << "AteClient::RegisterDevice";
Expand Down
8 changes: 8 additions & 0 deletions src/ate/ate_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,14 @@ class AteClient {
const size_t serial_number_size,
pa::CreateKeyAndCertResponse* reply);

// Calls the server's EndorseCerts method and returns its reply.
grpc::Status EndorseCerts(pa::EndorseCertsRequest& request,
pa::EndorseCertsResponse* reply);

// Calls the server's DeriveSymmetricKeys method and returns its reply.
grpc::Status DeriveSymmetricKeys(pa::DeriveSymmetricKeysRequest& request,
pa::DeriveSymmetricKeysResponse* reply);

// Calls the server's RegisterDevice method and returns its reply.
grpc::Status RegisterDevice(pa::RegistrationRequest& request,
pa::RegistrationResponse* reply);
Expand Down
50 changes: 50 additions & 0 deletions src/ate/ate_client_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ namespace {

using pa::CreateKeyAndCertRequest;
using pa::CreateKeyAndCertResponse;
using pa::DeriveSymmetricKeysRequest;
using pa::DeriveSymmetricKeysResponse;
using pa::EndorseCertsRequest;
using pa::EndorseCertsResponse;
using pa::MockProvisioningApplianceServiceStub;
using testing::_;
using testing::DoAll;
Expand Down Expand Up @@ -69,6 +73,52 @@ TEST_F(AteTest, CreateKeyAndCertCallsServer) {
EXPECT_THAT(result, EqualsProto(response));
}

TEST_F(AteTest, EndorseCerts) {
// Response that will be sent back for EndorseCerts.
auto response = ParseTextProto<EndorseCertsResponse>(R"pb(
certs: { blob: "fake-cert-blob" })pb");

// Expect EndorseCerts to be called.
// The 2nd arg is expected to be a protobuf with the `sku` field.
// We'll return the `response` struct and a status of `OK`.
EXPECT_CALL(*pa_service_, EndorseCerts(_, EqualsProto(R"pb(
sku: "abc123"
)pb"),
_))
.WillOnce(DoAll(SetArgPointee<2>(response), Return(grpc::Status::OK)));

EndorseCertsRequest request;
request.set_sku("abc123");

// Call the AteClient and verify it returns OK with the expected response.
EndorseCertsResponse result;
EXPECT_THAT(ate_->EndorseCerts(request, &result).ok(), IsTrue());
EXPECT_THAT(result, EqualsProto(response));
}

TEST_F(AteTest, DeriveSymmetricKeys) {
// Response that will be sent back for DeriveSymmetricKeys.
auto response = ParseTextProto<DeriveSymmetricKeysResponse>(R"pb(
keys: "fake-key-blob")pb");

// Expect DeriveSymmetricKeys to be called.
// The 2nd arg is expected to be a protobuf with the `sku` field.
// We'll return the `response` struct and a status of `OK`.
EXPECT_CALL(*pa_service_, DeriveSymmetricKeys(_, EqualsProto(R"pb(
sku: "abc123"
)pb"),
_))
.WillOnce(DoAll(SetArgPointee<2>(response), Return(grpc::Status::OK)));

DeriveSymmetricKeysRequest request;
request.set_sku("abc123");

// Call the AteClient and verify it returns OK with the expected response.
pa::DeriveSymmetricKeysResponse result;
EXPECT_THAT(ate_->DeriveSymmetricKeys(request, &result).ok(), IsTrue());
EXPECT_THAT(result, EqualsProto(response));
}

} // namespace
} // namespace ate
} // namespace provisioning
Loading

0 comments on commit 8fc4c5f

Please sign in to comment.