Skip to content

Commit

Permalink
Adding /agent/info API to agent
Browse files Browse the repository at this point in the history
Bumping API version to 2.2

Signed-off-by: Michael Peters <[email protected]>
  • Loading branch information
mpeters committed May 14, 2024
1 parent c91fba3 commit cb0c543
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 14 deletions.
80 changes: 80 additions & 0 deletions keylime-agent/src/agent_handler.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2023 Keylime Authors

use crate::common::JsonWrapper;
use crate::{tpm, Error as KeylimeError, QuoteData};
use actix_web::{web, HttpRequest, HttpResponse, Responder};
use base64::{engine::general_purpose, Engine as _};
use log::*;
use serde::{Deserialize, Serialize};
use std::{
fs::{read, read_to_string},
io::{Read, Seek},
};

#[derive(Serialize, Deserialize, Debug, Default)]
pub(crate) struct AgentInfo {
pub agent_uuid: String,
pub tpm_hash_alg: String,
pub tpm_enc_alg: String,
pub tpm_sign_alg: String,
pub ak_handle: u32,
}

// This is an Info request which gets some information about this keylime agent
// It should return a AgentInfo object as JSON
pub async fn info(
req: HttpRequest,
data: web::Data<QuoteData>,
) -> impl Responder {
debug!("Returning agent information");

let mut info = AgentInfo {
agent_uuid: data.agent_uuid.clone(),
tpm_hash_alg: data.hash_alg.to_string(),
tpm_enc_alg: data.enc_alg.to_string(),
tpm_sign_alg: data.sign_alg.to_string(),
ak_handle: data.ak_handle.value(),
};

let response = JsonWrapper::success(info);
info!("GET info returning 200 response");
HttpResponse::Ok().json(response)
}

#[cfg(test)]
#[cfg(feature = "testing")]
mod tests {
use super::*;
use crate::common::API_VERSION;
use actix_web::{test, web, App};

#[actix_rt::test]
async fn test_agent_info() {
let mut quotedata = QuoteData::fixture().unwrap(); //#[allow_ci]
quotedata.hash_alg = keylime::algorithms::HashAlgorithm::Sha256;
quotedata.enc_alg = keylime::algorithms::EncryptionAlgorithm::Rsa;
quotedata.sign_alg = keylime::algorithms::SignAlgorithm::RsaSsa;
quotedata.agent_uuid = "DEADBEEF".to_string();
let data = web::Data::new(quotedata);
let mut app =
test::init_service(App::new().app_data(data.clone()).route(
&format!("/{API_VERSION}/agent/info"),
web::get().to(info),
))
.await;

let req = test::TestRequest::get()
.uri(&format!("/{API_VERSION}/agent/info"))
.to_request();

let resp = test::call_service(&app, req).await;
assert!(resp.status().is_success());

let result: JsonWrapper<AgentInfo> = test::read_body_json(resp).await;
assert_eq!(result.results.agent_uuid.as_str(), "DEADBEEF");
assert_eq!(result.results.tpm_hash_alg.as_str(), "sha256");
assert_eq!(result.results.tpm_enc_alg.as_str(), "rsa");
assert_eq!(result.results.tpm_sign_alg.as_str(), "rsassa");
}
}
2 changes: 1 addition & 1 deletion keylime-agent/src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ use tss_esapi::{
/*
* Constants and static variables
*/
pub const API_VERSION: &str = "v2.1";
pub const API_VERSION: &str = "v2.2";
pub const TPM_DATA_PCR: usize = 16;
pub const IMA_PCR: usize = 10;
pub static RSA_PUBLICKEY_EXPORTABLE: &str = "rsa placeholder";
Expand Down
63 changes: 50 additions & 13 deletions keylime-agent/src/errors_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@ pub(crate) async fn app_default(req: HttpRequest) -> impl Responder {
http::Method::GET => {
error = 400;
message = format!(
"Not Implemented: Use /version or /{API_VERSION}/ interfaces"
"Not Implemented: Use /version or /{API_VERSION} interfaces"
);
response = HttpResponse::BadRequest()
.json(JsonWrapper::error(error, &message));
}
http::Method::POST => {
error = 400;
message =
format!("Not Implemented: Use /{API_VERSION}/ interface");
format!("Not Implemented: Use /{API_VERSION} interface");
response = HttpResponse::BadRequest()
.json(JsonWrapper::error(error, &message));
}
Expand Down Expand Up @@ -62,14 +62,15 @@ pub(crate) async fn api_default(req: HttpRequest) -> impl Responder {
match req.head().method {
http::Method::GET => {
error = 400;
message = "Not Implemented: Use /keys/ or /quotes/ interfaces";
message =
"Not Implemented: Use /agent, /keys, or /quotes interfaces";
response = HttpResponse::BadRequest()
.json(JsonWrapper::error(error, message));
}
http::Method::POST => {
error = 400;
message =
"Not Implemented: Use /keys/ or /notifications/ interfaces";
"Not Implemented: Use /keys or /notifications interfaces";
response = HttpResponse::BadRequest()
.json(JsonWrapper::error(error, message));
}
Expand Down Expand Up @@ -103,19 +104,19 @@ pub(crate) async fn keys_default(req: HttpRequest) -> impl Responder {
match req.head().method {
http::Method::GET => {
error = 400;
message = "URI not supported, only /pubkey and /verify are supported for GET in /keys/ interface";
message = "URI not supported, only /pubkey and /verify are supported for GET in /keys interface";
response = HttpResponse::BadRequest()
.json(JsonWrapper::error(error, message));
}
http::Method::POST => {
error = 400;
message = "URI not supported, only /ukey and /vkey are supported for POST in /keys/ interface";
message = "URI not supported, only /ukey and /vkey are supported for POST in /keys interface";
response = HttpResponse::BadRequest()
.json(JsonWrapper::error(error, message));
}
_ => {
error = 405;
message = "Method is not supported in /keys/ interface";
message = "Method is not supported in /keys interface";
response = HttpResponse::MethodNotAllowed()
.insert_header(http::header::Allow(vec![
http::Method::GET,
Expand Down Expand Up @@ -166,6 +167,37 @@ pub(crate) async fn quotes_default(req: HttpRequest) -> impl Responder {
response
}

pub(crate) async fn agent_default(req: HttpRequest) -> impl Responder {
let error;
let response;
let message;

match req.head().method {
http::Method::GET => {
error = 400;
message = "URI not supported, only /info is supported for GET in /agent interface";
response = HttpResponse::BadRequest()
.json(JsonWrapper::error(error, message));
}
_ => {
error = 405;
message = "Method is not supported in /agent interface";
response = HttpResponse::MethodNotAllowed()
.insert_header(http::header::Allow(vec![http::Method::GET]))
.json(JsonWrapper::error(error, message));
}
};

warn!(
"{} returning {} response. {}",
req.head().method,
error,
message
);

response
}

pub(crate) async fn notifications_default(
req: HttpRequest,
) -> impl Responder {
Expand Down Expand Up @@ -343,6 +375,11 @@ mod tests {
.await
}

#[actix_rt::test]
async fn test_agent_default() {
test_default(web::resource("/").to(agent_default), "GET").await
}

#[derive(Serialize, Deserialize)]
struct DummyQuery {
param: String,
Expand Down Expand Up @@ -395,10 +432,10 @@ mod tests {
.error_handler(path_parser_error),
)
.service(
web::resource("/v2.1/ok").route(web::get().to(dummy)),
web::resource("/v2.2/ok").route(web::get().to(dummy)),
)
.service(
web::resource("/v2.1/ok/{number}/{string}")
web::resource("/v2.2/ok/{number}/{string}")
.route(web::get().to(dummy_with_path)),
)
.service(
Expand All @@ -410,7 +447,7 @@ mod tests {

// Sanity well formed request
let req = test::TestRequest::get()
.uri("/v2.1/ok?param=Test")
.uri("/v2.2/ok?param=Test")
.set_json(&DummyPayload { field: 42 })
.to_request();

Expand All @@ -432,7 +469,7 @@ mod tests {

// Test JSON parsing error
let req = test::TestRequest::get()
.uri("/v2.1/ok?param=Test")
.uri("/v2.2/ok?param=Test")
.insert_header(http::header::ContentType::json())
.set_payload("Not JSON")
.to_request();
Expand All @@ -445,7 +482,7 @@ mod tests {

// Test Query parsing error
let req = test::TestRequest::get()
.uri("/v2.1/ok?test=query")
.uri("/v2.2/ok?test=query")
.set_json(&DummyPayload { field: 42 })
.to_request();
let resp = test::call_service(&app, req).await;
Expand All @@ -457,7 +494,7 @@ mod tests {

// Test Path parsing error
let req = test::TestRequest::get()
.uri("/v2.1/ok/something/42?test=query")
.uri("/v2.2/ok/something/42?test=query")
.set_json(&DummyPayload { field: 42 })
.to_request();
let resp = test::call_service(&app, req).await;
Expand Down
10 changes: 10 additions & 0 deletions keylime-agent/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
// missing_docs: there is many functions missing documentations for now
#![allow(unused, missing_docs)]

mod agent_handler;
mod common;
mod config;
mod error;
Expand Down Expand Up @@ -861,6 +862,15 @@ async fn main() -> Result<()> {
)
.service(
web::scope(&format!("/{API_VERSION}"))
.service(
web::scope("/agent")
.service(web::resource("/info").route(
web::get().to(agent_handler::info),
))
.default_service(web::to(
errors_handler::agent_default,
)),
)
.service(
web::scope("/keys")
.service(web::resource("/pubkey").route(
Expand Down

0 comments on commit cb0c543

Please sign in to comment.