Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding example C client application for Veraison challenge response exchange. #2

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.

Copyright 2022 Contributors to the Veraison project.
Copyright 2023 Contributors to the Veraison project.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,9 @@
# c-apiclient
Veraison API client implementation in C

This example makes use of curl library to make REST API invocations to the Veraison server.
It implements only Synchronous verification part of the challenge response sequence.

Building the Client: gcc -g -o client client.c evidence_helper.c -lcurl

Running the Client example : client -l 127.0.0.1 -t psa-evidence.cbor
86 changes: 86 additions & 0 deletions examples/client.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Copyright 2023 Contributors to the Veraison project.
// SPDX-License-Identifier: Apache-2.0

#include "evidence_helper.h"

void usage_print(void) {
printf("Usage: client -l <address of the veraison service> -t <token to be verified>\n");
printf(" default address for -l option is 127.0.0.1\n");
}

int main(int argc, char *argv[]) {
char evidence[1024]={0};
char *address="127.0.0.1"; /*default address is localhost*/
char port[] = "8080";
char *filename;
char *base_url=NULL;
char *attestation_result;
size_t attestation_result_size;
size_t url_size;
char *media_type="application/psa-attestation-token";
int opt;

if(argc == 1) {
printf("\n mention the token path using client -t <path> \n");
return -1;
}

/* Parse the command line options*/
while((opt=getopt(argc,argv,":lthm"))!=-1)
{
switch(opt)
{
case 'l':
if(argv[optind] == NULL) {
usage_print();
return -1;
}
address = argv[optind];
break;
case 't':
if(argv[optind] == NULL) {
usage_print();
return -1;
}
filename = argv[optind];
break;
case 'm':
if(argv[optind] == NULL) {
usage_print();
return -1;
}
filename = argv[optind];
break;
case 'h':
usage_print();
return -1;
case '?':
printf("unknown option: %c\n",optopt);
break;
}
}
url_size = strlen("http://:/challenge-response/v1/") + strlen(address) + strlen(port) + 1;
base_url = (char*)malloc(url_size);
snprintf(base_url, url_size, "http://%s:%s/challenge-response/v1/", address, port);

FILE *fp=fopen(filename,"rb");
int evidence_size;
if(fp==NULL) {
printf("\ntoken file not found\n");
return -1;
}
evidence_size = fread(evidence, 1 ,sizeof(evidence),fp);
fclose(fp);
int ret = submit_evidence(evidence, evidence_size, media_type, base_url, &attestation_result, &attestation_result_size);
if(ret){
printf("\nSubmit evidence failed\n");
return -1;
}
printf("\n%s\n",attestation_result);
free(attestation_result);
free(base_url);
return 0;
}



166 changes: 166 additions & 0 deletions examples/evidence_helper.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
// Copyright 2023 Contributors to the Veraison project.
// SPDX-License-Identifier: Apache-2.0

#include "curl/curl.h"
#include "curl/header.h"
#include "evidence_helper.h"

struct response {
char *data;
size_t size;
};

static size_t response_callback(void *contents, size_t size, size_t nmemb, void *userp)
{
size_t realsize = size * nmemb;
struct response *mem = (struct response *)userp;

char *ptr = realloc(mem->data, mem->size + realsize + 1);
if(!ptr) {
/* out of memory! */
printf("not enough memory (realloc returned NULL)\n");
return 0;
}
mem->data = ptr;
memcpy(&(mem->data[mem->size]), contents, realsize);
mem->size += realsize;
mem->data[mem->size] = 0;

return realsize;
}

int submit_evidence(const char *evidence, size_t evidence_sz, const char *media_type, const char *base_url, char **psession_object, size_t *psession_object_sz)
{
CURL *curl_handle;
CURLcode res;
struct curl_header *type;
char *uri_new;
struct response resp;
char *mt_header;
size_t mt_header_len;

resp.data = malloc(1); /* will be grown as needed by the realloc above */
resp.size = 0; /* no data at this point */

/* Initialize the curl library */
curl_handle = curl_easy_init();
if(!curl_handle) {
printf("\nCannot initialize Curl library \n");
return -1;
}

/* Create new session with the veraison service */
char *new_session="newSession?nonceSize=32";
char url[100];
size_t url_len = strlen(base_url) + strlen(new_session) + 1;

/* Create the URL to request a new Session */
snprintf(url, url_len, "%s%s", base_url, new_session);

/* Default is GET method , so we have to set this for POST */
res = curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDS, "");
if(res != CURLE_OK) {
printf("\nerror: %s\n", curl_easy_strerror(res));
return -1;
}
res = curl_easy_setopt(curl_handle, CURLOPT_URL, url);
if(res != CURLE_OK) {
printf("\nerror: %s\n", curl_easy_strerror(res));
return -1;
}

/* Set the callback to capture the reponse in memory */
res = curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, response_callback);
if(res != CURLE_OK) {
printf("\nerror: %s\n", curl_easy_strerror(res));
return -1;
}

res = curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&resp);
if(res != CURLE_OK) {
printf("\nerror: %s\n", curl_easy_strerror(res));
return -1;
}
res = curl_easy_perform(curl_handle); /* post away! */
if(res != CURLE_OK) {
printf("\nerror: %s\n", curl_easy_strerror(res));
return -1;
}

/* Send the token for verification using the session id
returned by the previous curl_easy_perform call.
The session id is returned under Location in the header */

struct curl_slist *headers = NULL;
char *new_url;
size_t new_url_size;

/* Extract the Session ID from the previous response*/
curl_easy_header(curl_handle, "Location", 0, CURLH_HEADER, -1, &type);

/*Create URL for token verification using the returned Session ID */
new_url_size = strlen(type->value) + strlen(base_url) + 1;
new_url = (char*)malloc(new_url_size);
snprintf(new_url, new_url_size, "%s%s", base_url, type->value);
res = curl_easy_setopt(curl_handle, CURLOPT_URL, new_url);
if(res != CURLE_OK) {
printf("\nerror: %s\n", curl_easy_strerror(res));
return -1;
}

/*Create the media type header using the passed media type string*/
mt_header_len = strlen(media_type) + strlen("Content-Type: ") + 1;
mt_header = (char *) malloc(mt_header_len);
snprintf(mt_header, mt_header_len, "Content-Type: %s", media_type);
headers = curl_slist_append(headers, mt_header);
/* Add other feilds of header*/
curl_slist_append(headers, "Host: veraison.example");
curl_slist_append(headers, "Accept: application/vnd.veraison.challenge-response-session+json");
res = curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, headers);
if(res != CURLE_OK) {
printf("\nerror: %s\n", curl_easy_strerror(res));
return -1;
}

/* Set the body of the HTTP request with the evidence*/
res = curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDSIZE, evidence_sz);
if(res != CURLE_OK) {
printf("\nerror: %s\n", curl_easy_strerror(res));
return -1;
}
res = curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDS, evidence);
if(res != CURLE_OK) {
printf("\nerror: %s\n", curl_easy_strerror(res));
return -1;
}

/* Set the callback to capture the reponse in memory */
res = curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, response_callback);
if(res != CURLE_OK) {
printf("\nerror: %s\n", curl_easy_strerror(res));
return -1;
}
res = curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&resp);
if(res != CURLE_OK) {
printf("\nerror: %s\n", curl_easy_strerror(res));
return -1;
}

res = curl_easy_perform(curl_handle); /* post away! */
if(res != CURLE_OK) {
printf("\nerror: %s\n", curl_easy_strerror(res));
return -1;
}

*psession_object_sz = resp.size;
*psession_object = malloc(*psession_object_sz);
memcpy(*psession_object, (char *)resp.data, *psession_object_sz);

cleanup :
free(resp.data);
free(mt_header);
free(new_url);
curl_slist_free_all(headers); /* free the header list */
curl_global_cleanup();
return 0;
}
8 changes: 8 additions & 0 deletions examples/evidence_helper.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#include <unistd.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int submit_evidence(const char *evidence, size_t evidence_sz, const char *media_type, const char *base_url, char **psession_object, size_t *psession_object_sz);