Skip to content

Commit

Permalink
NOISSUE - Fix attested TLS and attestation CLI (ultravioletrs#184)
Browse files Browse the repository at this point in the history
* update code to reflect updated libraries

* fix attestation CLI

* update manual test for attestation CLI
  • Loading branch information
danko-miladinovic authored Jul 30, 2024
1 parent 6d170e9 commit 24a76a1
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 34 deletions.
36 changes: 33 additions & 3 deletions cli/attestation.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (

"github.com/google/go-sev-guest/abi"
"github.com/google/go-sev-guest/proto/check"
"github.com/google/go-sev-guest/proto/sevsnp"
"github.com/google/go-sev-guest/validate"
"github.com/google/go-sev-guest/verify"
"github.com/google/go-sev-guest/verify/trust"
Expand Down Expand Up @@ -40,6 +41,8 @@ const (
size48 = 48
size64 = 64
attestationFilePath = "attestation.bin"
sevProductNameMilan = "Milan"
sevProductNameGenoa = "Genoa"
exampleJSONConfig = `
{
"rootOfTrust":{
Expand Down Expand Up @@ -366,7 +369,7 @@ func (cli *CLI) NewValidateAttestationValidationCmd() *cobra.Command {
"Hex-encoded SHA-384 hash values of trusted identity keys in AMD public key format",
)
cmd.Flags().StringVar(
&cfg.RootOfTrust.Product,
&cfg.RootOfTrust.ProductLine,
"product",
"",
"The AMD product name for the chip that generated the attestation report.",
Expand Down Expand Up @@ -394,6 +397,10 @@ func (cli *CLI) NewValidateAttestationValidationCmd() *cobra.Command {
log.Fatalf("Failed to mark flag as required: %s", err)
}

if err := cmd.MarkFlagRequired("product"); err != nil {
log.Fatalf("Failed to mark flag as required: %s", err)
}

return cmd
}

Expand All @@ -402,13 +409,36 @@ func verifyAndValidateAttestation(attestation []byte) error {
if err != nil {
return err
}
sopts.Product = cfg.Policy.Product

if cfg.Policy.Product == nil {
productName := sevsnp.SevProduct_SEV_PRODUCT_UNKNOWN
switch cfg.RootOfTrust.ProductLine {
case sevProductNameMilan:
productName = sevsnp.SevProduct_SEV_PRODUCT_MILAN
case sevProductNameGenoa:
productName = sevsnp.SevProduct_SEV_PRODUCT_GENOA
default:
}

if productName == sevsnp.SevProduct_SEV_PRODUCT_UNKNOWN {
return fmt.Errorf("product name must be %s or %s", sevProductNameMilan, sevProductNameGenoa)
}

sopts.Product = &sevsnp.SevProduct{
Name: productName,
}
} else {
sopts.Product = cfg.Policy.Product
}

sopts.Getter = &trust.RetryHTTPSGetter{
Timeout: timeout,
MaxRetryDelay: maxRetryDelay,
Getter: &trust.SimpleHTTPSGetter{},
}
attestationPB, err := abi.ReportCertsToProto(attestation)

// Only take the attestation report and ignore everything else.
attestationPB, err := abi.ReportCertsToProto(attestation[:abi.ReportSize])
if err != nil {
return err
}
Expand Down
16 changes: 9 additions & 7 deletions pkg/clients/grpc/connect.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,11 @@ const (
)

const (
cocosDirectory = ".cocos"
caBundleName = "ask_ark.pem"
productNameMilan = "Milan"
productNameGenoa = "Genoa"
cocosDirectory = ".cocos"
caBundleName = "ask_ark.pem"
productNameMilan = "Milan"
productNameGenoa = "Genoa"
attestationReportSize = 0x4A0
)

var (
Expand Down Expand Up @@ -185,7 +186,7 @@ func connect(cfg Config) (*grpc.ClientConn, security, error) {

opts = append(opts, grpc.WithTransportCredentials(tc))

conn, err := grpc.Dial(cfg.URL, opts...)
conn, err := grpc.NewClient(cfg.URL, opts...)
if err != nil {
return nil, secure, errors.Wrap(errGrpcConnect, err)
}
Expand Down Expand Up @@ -247,7 +248,8 @@ func verifyAttestationReportTLS(rawCerts [][]byte, verifiedChains [][]*x509.Cert
Getter: &trust.SimpleHTTPSGetter{},
}

attestationPB, err := abi.ReportCertsToProto(ext.Value)
attestation_bytes := ext.Value[:attestationReportSize]
attestationPB, err := abi.ReportCertsToProto(attestation_bytes)
if err != nil {
return errors.Wrap(errAttVerification, err)
}
Expand Down Expand Up @@ -293,7 +295,7 @@ func checkIfCertificateSelfSigned(cert *x509.Certificate) error {
}

func fillInAttestationLocal(attestation *sevsnp.Attestation) error {
product := attestationConfiguration.RootOfTrust.Product
product := attestationConfiguration.RootOfTrust.ProductLine

chain := attestation.GetCertificateChain()
if chain == nil {
Expand Down
11 changes: 8 additions & 3 deletions pkg/progressbar/progressbar.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@ const (
)

var (
_ streamSender = (*algoClientWrapper)(nil)
_ streamSender = (*dataClientWrapper)(nil)
_ streamSender = (*algoClientWrapper)(nil)
_ streamSender = (*dataClientWrapper)(nil)
warnOnlyOnce = false
)

type streamSender interface {
Expand Down Expand Up @@ -192,7 +193,11 @@ func (p *ProgressBar) renderProgressBar() error {
// Get terminal width.
width, err := terminalWidth()
if err != nil {
return err
if !warnOnlyOnce {
fmt.Println("Progress bar could not be rendered")
warnOnlyOnce = true
}
return nil
}

if p.maxWidth < width {
Expand Down
2 changes: 0 additions & 2 deletions scripts/backend_info/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,3 @@ clap = { version = "4.0", features = ["derive"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
sev = "3.1.1"
sysinfo = "0.30.12"
regex = "1.10.4"
78 changes: 60 additions & 18 deletions scripts/backend_info/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,27 @@
use clap::{Arg, Command, value_parser};
use serde::Serialize;
use std::arch::x86_64::__cpuid;
use std::fs::File;
use std::io::Write;
use sysinfo::System;
use regex::Regex;
use sev::firmware::host::*;

const BACKEND_INFO_JSON : &str = "backend_info.json";
const EXTENDED_FAMILY_SHIFT: u32 = 20;
const EXTENDED_MODEL_SHIFT: u32 = 16;
const FAMILY_SHIFT: u32 = 8;
const SEV_EXTENDED_FAMILY: u32 = 0xA;
const SEV_FAMILY: u32 = 0xF;
const MILAN_EXTENDED_MODEL: u32 = 0x0;
const GENOA_EXTENDED_MODEL: u32 = 0x1;

const SEV_PRODUCT_UNKNOWN: i32 = 0;
const SEV_PRODUCT_MILAN: i32 = 1;
const SEV_PRODUCT_GENOA: i32 = 2;

#[derive(Clone, Copy, Serialize)]
struct SevProduct {
name: i32,
}

#[derive(Serialize)]
struct Vmpl {
Expand All @@ -30,13 +45,15 @@ struct SnpPolicy {
minimum_version: String,
permit_provisional_firmware: bool,
require_id_block: bool,
product: SevProduct,
}

#[derive(Serialize)]
struct RootOfTrust {
product: String,
check_crl : bool,
disallow_network : bool,
product_line : String,
}

#[derive(Serialize)]
Expand All @@ -45,30 +62,52 @@ struct Computation {
root_of_trust: RootOfTrust,
}

fn get_product_name() -> String {
let mut sys = System::new_all();
sys.refresh_all();

let re = Regex::new(r"EPYC.*7..3.*").unwrap();
fn get_sev_snp_processor() -> u32 {
let cpuid_result = unsafe { __cpuid(1)};
cpuid_result.eax
}

for cpu in sys.cpus() {
if re.is_match(cpu.brand()) {
return "Milan".to_string()
}
fn get_product_name(product: i32) -> String {
match product {
SEV_PRODUCT_MILAN => return "Milan".to_string(),
SEV_PRODUCT_GENOA => return "Genoa".to_string(),
_ => return "Unknown".to_string(),
}

"Unknown".to_string()
}

fn get_uint64_from_tcb(tcb_version : &TcbVersion) -> u64 {
let microcode = (tcb_version.microcode as u64) << 56;
let snp = (tcb_version.snp as u64) << 48;
let tee = (tcb_version.tee as u64) << 8;
let bootloader = tcb_version.bootloader as u64;
let bootloader: u64 = tcb_version.bootloader as u64;

microcode | snp | tee | bootloader
}

fn sev_product(eax: u32) -> SevProduct {
let extended_family = (eax >> EXTENDED_FAMILY_SHIFT) & 0xff;
let extended_model = (eax >> EXTENDED_MODEL_SHIFT) & 0xf;
let family = (eax >> FAMILY_SHIFT) & 0xf;

let mut product_name = SEV_PRODUCT_UNKNOWN;

if extended_family == SEV_EXTENDED_FAMILY && family == SEV_FAMILY {
product_name = match extended_model {
MILAN_EXTENDED_MODEL => SEV_PRODUCT_MILAN,
GENOA_EXTENDED_MODEL => SEV_PRODUCT_GENOA,
_ => {
return SevProduct {
name: SEV_PRODUCT_UNKNOWN,
};
}
};
}

SevProduct {
name: product_name,
}
}

fn main() {
let matches = Command::new("Backend info")
.about("Processes command line options and outputs a JSON file for Attestation verification")
Expand All @@ -84,21 +123,22 @@ fn main() {
let status: SnpPlatformStatus = firmware.snp_platform_status().unwrap();

let policy: u64 = *matches.get_one::<u64>("policy").unwrap();
let family_id = vec![0];
let image_id = vec![0];
let family_id = vec![0; 16];
let image_id = vec![0; 16];
let vmpl = Vmpl { value: 0};
let minimum_tcb = get_uint64_from_tcb(&status.platform_tcb_version);
let minimum_launch_tcb = get_uint64_from_tcb(&status.platform_tcb_version);
let require_author_key = false;
let measurement = vec![0];
let host_data = vec![0];
let report_id_ma = vec![0];
let report_id_ma = vec![0xFF; 32];
let cpu_id: Identifier = firmware.get_identifier().unwrap();
let chip_id: Vec<u8> = cpu_id.0;
let minimum_build = status.build_id;
let minimum_version = status.version.to_string();
let permit_provisional_firmware = false;
let require_id_block = false;
let product = sev_product(get_sev_snp_processor());

let snp_policy = SnpPolicy {
policy,
Expand All @@ -116,12 +156,14 @@ fn main() {
minimum_version,
permit_provisional_firmware,
require_id_block,
product,
};

let root_of_trust = RootOfTrust {
product : get_product_name(),
product : get_product_name(product.name),
check_crl : true,
disallow_network : false,
product_line : get_product_name(product.name),
};

let computation = Computation {
Expand Down
3 changes: 2 additions & 1 deletion test/manual/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ export AGENT_GRPC_ATTESTED_TLS=true
go run cmd/cli/main.go attestation get '<report_data>'

# Validate Attestation
go run cmd/cli/main.go attestation validate '<attesation>' --report_data '<report_data>'
# Product name must be Milan or Genoa
go run cmd/cli/main.go attestation validate '<attesation>' --report_data '<report_data>' --product <product_name>

# Run the CLI program with algorithm input
go run cmd/cli/main.go algo test/manual/algo/lin_reg.bin <private_key_file_path>
Expand Down

0 comments on commit 24a76a1

Please sign in to comment.