Skip to content

Commit

Permalink
init/tee: Add snp_attest() and KBS CHALLENGE
Browse files Browse the repository at this point in the history
The initial phase of a KBS attestation is the CHALLENGE. The CHALLENGE
serves as the function that an attestation server uses to generate an
ephermal nonce and send it back to the client for inclusion in the
SNP attestation report.

Signed-off-by: Tyler Fanelli <[email protected]>
  • Loading branch information
tylerfanelli authored and slp committed Mar 10, 2023
1 parent 742c212 commit eace3c8
Show file tree
Hide file tree
Showing 8 changed files with 352 additions and 5 deletions.
17 changes: 15 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,23 @@ INIT_BINARY = init/init
ABI_VERSION=1
FULL_VERSION=1.5.1

INIT_SRC = init/init.c
SNP_INIT_SRC = init/tee/snp_attest.c \
init/tee/snp_attest.h \
init/tee/kbs/kbs.h \
init/tee/kbs/kbs_util.c \
init/tee/kbs/kbs_types.c \
init/tee/kbs/kbs_curl.c \

SEV_LD_FLAGS = -lcurl -lidn2 -lssl -lcrypto -lzstd -lz -lbrotlidec-static \
-lbrotlicommon-static

ifeq ($(SEV),1)
VARIANT = -sev
FEATURE_FLAGS := --features amd-sev
INIT_DEFS := -DSEV=1
INIT_DEFS += $(SEV_LD_FLAGS)
INIT_SRC += $(SNP_INIT_SRC)
endif

INIT_DEFS =
Expand Down Expand Up @@ -46,8 +59,8 @@ all: $(LIBRARY_RELEASE_$(OS)) libkrun.pc

debug: $(LIBRARY_DEBUG_$(OS)) libkrun.pc

$(INIT_BINARY): init/init.c
gcc -O2 -static -Wall $(INIT_DEFS) -o $@ init/init.c
$(INIT_BINARY): $(INIT_SRC)
gcc -O2 -static -Wall $(INIT_DEFS) -o $@ $(INIT_SRC) $(INIT_DEFS)

$(LIBRARY_RELEASE_$(OS)): $(INIT_BINARY)
cargo build --release $(FEATURE_FLAGS)
Expand Down
11 changes: 8 additions & 3 deletions init/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@

#include "jsmn.h"

#include "tee/snp_attest.h"

#define CMDLINE_SECRET_PATH "/sfs/secrets/coco/cmdline"
#define CONFIG_FILE_PATH "/.krun_config.json"
#define MAX_ARGS 32
Expand Down Expand Up @@ -211,11 +213,14 @@ static char *get_luks_passphrase(int *pass_len)
pass = (char *) malloc(MAX_PASS_SIZE);
if (pass == NULL)
goto umount_teeconfig;
*pass_len = 0;

goto free_pass;
if (snp_attest(pass, url, wid) == 0) {
return_str = pass;
*pass_len = strlen(pass);

goto umount_teeconfig;
}

free_pass:
free(pass);

umount_teeconfig:
Expand Down
35 changes: 35 additions & 0 deletions init/tee/kbs/kbs.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// SPDX-License-Identifier: Apache-2.0

#ifndef _KBS
#define _KBS

#include <curl/curl.h>

// kbs_util.c
char *tee_str(int);

/*
* Identifiers for all possible TEE architectures.
*/
enum tee {
TEE_SEV,
TEE_SGX,
TEE_SNP,
TEE_TDX,
};

/*
* The type of KBS operation to be performed.
*/
enum curl_post_type {
KBS_CURL_REQ,
};

// kbs_types.c
int kbs_request_marshal(char *, int, char *);
int kbs_challenge(CURL *, char *, char *, char *);

// kbs_curl.c
int kbs_curl_post(CURL *, char *, char *, char *, int);

#endif /* _KBS */
164 changes: 164 additions & 0 deletions init/tee/kbs/kbs_curl.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
// SPDX-License-Identifier: Apache-2.0

#include <stdio.h>
#include <string.h>
#include <curl/curl.h>

#include "kbs.h"

static CURLcode kbs_curl_set_headers(CURL *, char *);
static int KBS_CURL_ERR(char *);
size_t curl_write(void *, size_t, size_t, void *);

static int kbs_curl_post_request(CURL *, char *, char *, char *);

/*
* Complete a cURL POST request. POST the "in" string and retrieve the contents
* of the POST request "out" string.
*
* Depending on the type of request, some extra headers may need to be set.
* For example, on a KBS REQUEST, no session ID has been retrieved from the
* attestation server so far. Yet, during a KBS_ATTEST request, a session ID
* has been given from the server and must be added to the headers.
*/
int
kbs_curl_post(CURL *curl, char *url, char *in, char *out, int type)
{
CURLcode code;

/*
* Neither the input or output strings should be invalid/NULL.
*/
if (!in)
return KBS_CURL_ERR("Input argument NULL");

if (!out)
return KBS_CURL_ERR("Output argument NULL");

/*
* Specify the following cURL operations/attributes:
* * Headers
* * POST operation
* * Write function
*/
code = kbs_curl_set_headers(curl, NULL);
if (code != CURLE_OK)
return KBS_CURL_ERR("CURLOPT_HTTPHEADER");

code = curl_easy_setopt(curl, CURLOPT_POST, 1L);
if (code != CURLE_OK)
return KBS_CURL_ERR("CURLOPT_POST");

code = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_write);
if (code != CURLE_OK)
return KBS_CURL_ERR("CURLOPT_WRITEFUNCTION");

/*
* Based on the operation TYPE, there will need to be some additional
* cURL attributes set. These will also perform the cURL request.
*/
switch (type) {
case KBS_CURL_REQ:
return kbs_curl_post_request(curl, url, in, out);
default:
return KBS_CURL_ERR("Type argument invalid");
}
}

/*
* Set the cURL headers. If the session args is not NULL, that indicates that
* the session ID has been retrieved from attestation server before, and that
* session ID should be included in the headers.
*/
static CURLcode
kbs_curl_set_headers(CURL *curl, char *session)
{
struct curl_slist *slist;
char session_buf[100];

slist = NULL;
slist = curl_slist_append(slist, "Accept: application/json");
slist = curl_slist_append(slist,
"Content-Type: application/json; charset=utf-8");

/*
* Add the session ID cookie if the session ID exists.
*/
if (session) {
sprintf(session_buf, "Cookie: session_id=%s", session);
curl_slist_append(slist, session_buf);
}

/*
* Set the headers.
*/
return curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist);
}

/*
* POST a KBS REQUEST and attempt to retrieve a nonce from the attestation
* server.
*/
static int
kbs_curl_post_request(CURL *curl, char *url, char *req, char *nonce)
{
CURLcode code;
char req_url[100];

/*
* Set the cURL POST URL to $URL/kbs/v0/auth.
*/
sprintf(req_url, "%s/kbs/v0/auth", url);

code = curl_easy_setopt(curl, CURLOPT_URL, req_url);
if (code != CURLE_OK)
return KBS_CURL_ERR("CURLOPT_URL");

/*
* Set the KBS REQUEST size and data.
*/
code = curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long) strlen(req));
if (code != CURLE_OK)
return KBS_CURL_ERR("CURLOPT_POSTFIELDSIZE");

code = curl_easy_setopt(curl, CURLOPT_POSTFIELDS, req);
if (code != CURLE_OK)
return KBS_CURL_ERR("CURLOPT_POSTFIELDS");

/*
* We would like the nonce written to the "nonce" argument.
*/
code = curl_easy_setopt(curl, CURLOPT_WRITEDATA, nonce);
if (code != CURLE_OK)
return KBS_CURL_ERR("CURLOPT_WRITEDATA");

code = curl_easy_perform(curl);
if (code != CURLE_OK && code != CURLE_WRITE_ERROR)
return KBS_CURL_ERR("CURL_EASY_PERFORM");

return 0;
}

/*
* Based on the given cURL error, print the KBS error and return an error
* indicator.
*/
static int
KBS_CURL_ERR(char *errmsg)
{
printf("ERROR (kbs_curl_post): %s\n", errmsg);

return -1;
}

/*
* Simple strcpy() for attestation server responses. Required by a cURL
* operation that writes data.
*/
size_t
curl_write(void *data, size_t size, size_t nmemb, void *userp)
{
strcpy((char *) userp, (char *) data);

return size;
}
52 changes: 52 additions & 0 deletions init/tee/kbs/kbs_types.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// SPDX-License-Identifier: Apache-2.0

#include <stdio.h>

#include "kbs.h"

/*
* Given a TEE architecture and workload ID, write the JSON string of the
* KBS REQUEST.
*/
int
kbs_request_marshal(char *json_request, int tee, char *workload_id)
{
char *teestr;

/*
* Retrieve the KBS string equivalent of the TEE enum value.
*/
teestr = tee_str(tee);
if (teestr == NULL)
return -1;

/*
* Build the KBS REQUEST JSON string.
*/
sprintf(json_request,
"{\"extra-params\":\"{\\\"workload_id\\\":\\\"%s\\\"}\",\"tee\":\"%s\",\"version\":\"0.0.0\"}",
workload_id,
teestr);

return 0;
}

/*
* Peform a KBS CHALLENGE.
*
* "json_request" is the JSON string of the KBS REQUEST.
* "nonce" is the output argument to be retrieved from the attestation server.
*/
int
kbs_challenge(CURL *curl, char *url, char *json_request, char *nonce)
{
int ret;

ret = kbs_curl_post(curl, url, (void *) json_request, (void *) nonce, KBS_CURL_REQ);
if (ret < 0) {
printf("ERROR: could not complete KBS challenge\n");
return -1;
}

return 0;
}
30 changes: 30 additions & 0 deletions init/tee/kbs/kbs_util.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// SPDX-License-Identifier: Apache-2.0

#include <stdio.h>

#include "kbs.h"

/*
* Return the string identifier of the inputted TEE architecture.
*/
char *
tee_str(int tee)
{
switch (tee) {
case TEE_SEV:
return "sev";
case TEE_SGX:
return "sgx";
case TEE_SNP:
return "snp";
case TEE_TDX:
return "tdx";

/*
* No other TEE architecture is supported.
*/
default:
printf("ERROR: tee_str(): Invalid input\n");
return NULL;
}
}
39 changes: 39 additions & 0 deletions init/tee/snp_attest.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// SPDX-License-Identifier: Apache-2.0

#include <stdio.h>
#include <stddef.h>

#include "snp_attest.h"
#include "kbs/kbs.h"

#define NONCE_MAX 1024
#define JSON_MAX 1024

static int SNP_ATTEST_ERR(char *);

int
snp_attest(char *pass, char *url, char *wid)
{
CURL *curl;
char nonce[NONCE_MAX], json[JSON_MAX];

if (kbs_request_marshal(json, TEE_SNP, wid) < 0)
return SNP_ATTEST_ERR("Unable to marshal KBS REQUEST");

curl = curl_easy_init();
if (curl == NULL)
return SNP_ATTEST_ERR("Unable to initialize cURL instance");

if (kbs_challenge(curl, url, json, nonce) < 0)
return SNP_ATTEST_ERR("Unable to retrieve nonce from server");

return 0;
}

static int
SNP_ATTEST_ERR(char *errmsg)
{
printf("SNP ATTEST ERROR: %s\n", errmsg);

return -1;
}
9 changes: 9 additions & 0 deletions init/tee/snp_attest.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// SPDX-License-Identifier: Apache-2.0

#ifndef _SNP_ATTEST
#define _SNP_ATTEST

// snp_attest.c
int snp_attest(char *, char *, char *);

#endif /* _SNP_ATTEST */

0 comments on commit eace3c8

Please sign in to comment.