Skip to content

Instantly share code, notes, and snippets.

@haraldh
Created December 8, 2020 15:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save haraldh/9ef6f03987e9c22d9ee41f2ca88e55ad to your computer and use it in GitHub Desktop.
Save haraldh/9ef6f03987e9c22d9ee41f2ca88e55ad to your computer and use it in GitHub Desktop.
use ::sev::certs::{ca, sev};
use ::sev::launch::Policy;
use ::sev::session::Session;
use codicon::{Decoder, Encoder};
use koine::attestation::sev::*;
use process_control::{ChildExt, Timeout};
use serde::de::Deserialize;
use serde_cbor as serde_flavor;
use std::convert::TryFrom;
use std::os::unix::net::{UnixListener, UnixStream};
use std::process::{exit, Command, Stdio};
use std::thread;
use std::time::Duration;
const TIMEOUT_SECS: u64 = 100;
const DIGEST: [u8; 32] = [
171, 137, 63, 183, 79, 113, 206, 32, 82, 187, 235, 156, 158, 168, 181, 49, 243, 102, 178, 74,
22, 242, 132, 204, 168, 84, 98, 63, 151, 249, 142, 229,
];
const CLEARTEXT: &'static str = "\
Hello World!!Hello World!!Hello World!!Hello World!!Hello World!!Hello World!!Hello World!!\
Hello World!!Hello World!\
";
fn usage() -> String {
eprintln!("Usage: {} <path> -- rest", std::env::args().nth(0).unwrap());
exit(1);
}
fn main() -> std::io::Result<()> {
let path = std::env::args().nth(1).unwrap_or_else(usage);
if std::env::args().nth(2).unwrap_or_else(usage) != "--" {
usage();
}
let prog = std::env::args().nth(3).unwrap_or_else(usage);
let prog_args: Vec<String> = std::env::args().skip(4).collect();
println!("{}: {:?}", prog, prog_args);
if let Err(e) = std::fs::remove_file(&path) {
if e.kind() != std::io::ErrorKind::NotFound {
return Err(e);
}
}
let listener = UnixListener::bind(path)?;
let handle = thread::spawn(move || {
let child = Command::new(&prog)
.args(prog_args)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.unwrap_or_else(|e| panic!("failed to run `{}`: {:#?}", &prog, e));
let output = child
.with_output_timeout(Duration::from_secs(TIMEOUT_SECS))
.terminating()
.wait()
.unwrap_or_else(|e| panic!("failed to run `{}`: {:#?}", &prog, e))
.unwrap_or_else(|| panic!("process `{}` timed out", &prog));
let exit_status = output.status.code().unwrap_or_else(|| {
panic!(
"process `{}` terminated by signal {:?}",
&prog,
output.status.signal()
)
});
assert_eq!(exit_status, 0, "Expected exit status differs.");
let out: &[u8] = serde_flavor::from_slice(&output.stdout).expect("CBOR encoded secret");
println!("Output: {:#?}", String::from_utf8(out.to_vec()));
});
// accept connections and process them, spawning a new thread for each one
for stream in listener.incoming() {
match stream {
Ok(stream) => {
/* connection succeeded */
let launch_handle = thread::spawn(|| launch(stream));
handle.join().expect("join failed");
launch_handle.join().expect("join on launch failed");
exit(0);
}
Err(err) => {
panic!(err);
}
}
}
Ok(())
}
pub fn launch(sock: UnixStream) {
let mut de = serde_flavor::Deserializer::from_reader(&sock);
let chain_packet =
Message::deserialize(&mut de).expect("failed to deserialize expected certificate chain");
let chain_packet = match chain_packet {
Message::CertificateChainNaples(chain) => chain,
Message::CertificateChainRome(chain) => chain,
_ => panic!("expected certificate chain"),
};
let chain = ::sev::certs::Chain {
ca: ca::Chain {
ark: ca::Certificate::decode(chain_packet.ark.as_slice(), ()).expect("ark"),
ask: ca::Certificate::decode(chain_packet.ask.as_slice(), ()).expect("ask"),
},
sev: sev::Chain {
pdh: sev::Certificate::decode(chain_packet.pdh.as_slice(), ()).expect("pdh"),
pek: sev::Certificate::decode(chain_packet.pek.as_slice(), ()).expect("pek"),
cek: sev::Certificate::decode(chain_packet.cek.as_slice(), ()).expect("cek"),
oca: sev::Certificate::decode(chain_packet.oca.as_slice(), ()).expect("oca"),
},
};
let policy = Policy::default();
let session = Session::try_from(policy).expect("failed to craft policy");
let start = session.start(chain).expect("failed to start session");
let mut ls = LaunchStart {
policy: vec![],
cert: vec![],
session: vec![],
};
serde_flavor::to_writer(&mut ls.policy, &start.policy).expect("failed to serialize policy");
start
.cert
.encode(&mut ls.cert, ())
.expect("start cert encode");
serde_flavor::to_writer(&mut ls.session, &start.session).expect("failed to serialize session");
let start_packet = Message::LaunchStart(ls);
serde_flavor::to_writer(&sock, &start_packet).expect("failed to serialize launch start");
let msr =
Message::deserialize(&mut de).expect("failed to deserialize expected measurement packet");
assert!(matches!(msr, Message::Measurement(_)));
let secret_packet = if let Message::Measurement(msr) = msr {
let build: ::sev::Build =
serde_flavor::from_slice(&msr.build).expect("failed to deserialize build");
let measurement: ::sev::launch::Measurement =
serde_flavor::from_slice(&msr.measurement).expect("failed to deserialize measurement");
let session = session
.verify(&DIGEST, build, measurement)
.expect("verify failed");
let ct_vec = CLEARTEXT.as_bytes().to_vec();
let mut ct_enc = Vec::new();
serde_flavor::ser::to_writer(&mut ct_enc, &serde_cbor::value::Value::Bytes(ct_vec))
.expect("failed to encode secret");
let secret = session
.secret(::sev::launch::HeaderFlags::default(), &ct_enc)
.expect("gen_secret failed");
println!("Sent secret: {:?}", CLEARTEXT);
println!("Sent secret len: {}", ct_enc.len());
let s_enc = serde_flavor::to_vec(&secret).expect("failed to serialize secret to vector");
Message::Secret(s_enc)
} else {
Message::Secret(vec![])
};
serde_flavor::to_writer(&sock, &secret_packet).expect("failed to serialize secret packet");
let fin = Message::deserialize(&mut de).expect("failed to deserialize expected finish packet");
assert!(matches!(fin, Message::Finish(_)));
}
@MikeCamel
Copy link

Where does DIGEST come from, please?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment