diff --git a/cli/attestation.go b/cli/attestation.go index a9fd80c0..37c5d6c6 100644 --- a/cli/attestation.go +++ b/cli/attestation.go @@ -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" @@ -40,6 +41,8 @@ const ( size48 = 48 size64 = 64 attestationFilePath = "attestation.bin" + sevProductNameMilan = "Milan" + sevProductNameGenoa = "Genoa" exampleJSONConfig = ` { "rootOfTrust":{ @@ -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.", @@ -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 } @@ -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 } diff --git a/pkg/clients/grpc/connect.go b/pkg/clients/grpc/connect.go index c7fc86a4..c3407cdc 100644 --- a/pkg/clients/grpc/connect.go +++ b/pkg/clients/grpc/connect.go @@ -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 ( @@ -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) } @@ -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) } @@ -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 { diff --git a/pkg/progressbar/progressbar.go b/pkg/progressbar/progressbar.go index c809ee1e..cd25e2c3 100644 --- a/pkg/progressbar/progressbar.go +++ b/pkg/progressbar/progressbar.go @@ -24,8 +24,9 @@ const ( ) var ( - _ streamSender = (*algoClientWrapper)(nil) - _ streamSender = (*dataClientWrapper)(nil) + _ streamSender = (*algoClientWrapper)(nil) + _ streamSender = (*dataClientWrapper)(nil) + warnOnlyOnce = false ) type streamSender interface { @@ -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 { diff --git a/scripts/backend_info/Cargo.toml b/scripts/backend_info/Cargo.toml index 2c967875..2eecad83 100644 --- a/scripts/backend_info/Cargo.toml +++ b/scripts/backend_info/Cargo.toml @@ -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" diff --git a/scripts/backend_info/src/main.rs b/scripts/backend_info/src/main.rs index fd797b26..4657153e 100644 --- a/scripts/backend_info/src/main.rs +++ b/scripts/backend_info/src/main.rs @@ -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 { @@ -30,6 +45,7 @@ struct SnpPolicy { minimum_version: String, permit_provisional_firmware: bool, require_id_block: bool, + product: SevProduct, } #[derive(Serialize)] @@ -37,6 +53,7 @@ struct RootOfTrust { product: String, check_crl : bool, disallow_network : bool, + product_line : String, } #[derive(Serialize)] @@ -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") @@ -84,21 +123,22 @@ fn main() { let status: SnpPlatformStatus = firmware.snp_platform_status().unwrap(); let policy: u64 = *matches.get_one::("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 = 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, @@ -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 { diff --git a/test/manual/README.md b/test/manual/README.md index b231baf7..4dda590c 100644 --- a/test/manual/README.md +++ b/test/manual/README.md @@ -68,7 +68,8 @@ export AGENT_GRPC_ATTESTED_TLS=true go run cmd/cli/main.go attestation get '' # Validate Attestation -go run cmd/cli/main.go attestation validate '' --report_data '' +# Product name must be Milan or Genoa +go run cmd/cli/main.go attestation validate '' --report_data '' --product # Run the CLI program with algorithm input go run cmd/cli/main.go algo test/manual/algo/lin_reg.bin