use std::io::{Read, Result as IoResult, Write};
use time::OffsetDateTime;
use time::macros::format_description;
use abi::{SIGSTRUCT_HEADER1, SIGSTRUCT_HEADER2};
pub use abi::{Attributes, AttributesFlags, Miscselect, Sigstruct};
use crypto::{Hash, SgxHashOps, SgxRsaOps, SgxRsaPubOps};
use sgxs::{copy_measured, SgxsRead};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct EnclaveHash {
hash: Hash,
}
impl EnclaveHash {
pub fn new(hash: Hash) -> Self {
EnclaveHash { hash }
}
pub fn hash(&self) -> Hash {
self.hash
}
pub fn from_stream<R: SgxsRead, H: SgxHashOps>(stream: &mut R) -> Result<Self, anyhow::Error> {
struct WriteToHasher<H> {
hasher: H,
}
impl<H: SgxHashOps> Write for WriteToHasher<H> {
fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
self.hasher.update(buf);
Ok(buf.len())
}
fn flush(&mut self) -> IoResult<()> {
Ok(())
}
}
let mut out = WriteToHasher { hasher: H::new() };
copy_measured(stream, &mut out)?;
Ok(Self::new(out.hasher.finish()))
}
}
pub fn verify<K: SgxRsaOps, H: SgxHashOps>(sig: &Sigstruct, key: &K) -> Result<(), K::Error> {
Signer::check_key(key);
key.verify_sha256_pkcs1v1_5(&sig.signature[..], Signer::sighash::<H>(sig))
}
#[derive(Clone, Debug)]
pub struct Signer {
date: u32,
swdefined: u32,
miscselect: Miscselect,
miscmask: u32,
attributes: Attributes,
attributemask: [u64; 2],
isvprodid: u16,
isvsvn: u16,
enclavehash: EnclaveHash,
}
impl Signer {
pub fn new(enclavehash: EnclaveHash) -> Signer {
let format = format_description!("[Year][month][day]");
let now = OffsetDateTime::now_utc()
.format(&format)
.unwrap()
.to_string();
Signer {
date: u32::from_str_radix(&now, 16).unwrap(),
swdefined: 0,
miscselect: Miscselect::default(),
miscmask: !0,
attributes: Attributes {
flags: abi::AttributesFlags::MODE64BIT,
xfrm: 0x3,
},
attributemask: [!abi::AttributesFlags::DEBUG.bits(), !0x3],
isvprodid: 0,
isvsvn: 0,
enclavehash,
}
}
fn check_key<K: SgxRsaOps>(key: &K) {
if key.len() != 3072 {
panic!("Key size is not 3072 bits");
}
if key.e() != [3] {
panic!("Key public exponent is not 3");
}
}
fn sighash<H: SgxHashOps>(sig: &Sigstruct) -> Hash {
let mut hasher = H::new();
let data = sig.signature_data();
hasher.update(data.0);
hasher.update(data.1);
hasher.finish()
}
pub fn unsigned_hash<H: SgxHashOps>(&self) -> Hash {
let sig = Self::unsigned_sig(self);
Self::sighash::<H>(&sig)
}
pub fn unsigned_sig(&self) -> Sigstruct {
let sig = Sigstruct {
header: SIGSTRUCT_HEADER1,
vendor: 0,
date: self.date,
header2: SIGSTRUCT_HEADER2,
swdefined: self.swdefined,
_reserved1: [0; 84],
modulus: [0; 384],
exponent: 3,
signature: [0; 384],
miscselect: self.miscselect,
miscmask: self.miscmask,
_reserved2: [0; 20],
attributes: self.attributes,
attributemask: self.attributemask,
enclavehash: self.enclavehash.hash,
_reserved3: [0; 32],
isvprodid: self.isvprodid,
isvsvn: self.isvsvn,
_reserved4: [0; 12],
q1: [0; 384],
q2: [0; 384],
};
sig
}
pub fn sign<K: SgxRsaOps, H: SgxHashOps>(self, key: &K) -> Result<Sigstruct, K::Error> {
Self::check_key(key);
let mut sig = Self::unsigned_sig(&self);
let (s, q1, q2) = key.sign_sha256_pkcs1v1_5_with_q1_q2(Self::sighash::<H>(&sig))?;
let n = key.n();
(&mut sig.modulus[..]).write_all(&n).unwrap();
(&mut sig.signature[..]).write_all(&s).unwrap();
(&mut sig.q1[..]).write_all(&q1).unwrap();
(&mut sig.q2[..]).write_all(&q2).unwrap();
Ok(sig)
}
pub fn cat_sign<K: SgxRsaPubOps + SgxRsaOps>(
&self,
key: &K,
mut s_vec: Vec<u8>,
) -> Result<Sigstruct, <K as SgxRsaPubOps>::Error> {
Self::check_key(key);
let mut sig = Self::unsigned_sig(&self);
let (q1, q2) = key.calculate_q1_q2(&s_vec)?;
s_vec.reverse();
let n = key.n();
(&mut sig.modulus[..]).write_all(&n).unwrap();
(&mut sig.signature[..]).write_all(&s_vec).unwrap();
(&mut sig.q1[..]).write_all(&q1).unwrap();
(&mut sig.q2[..]).write_all(&q2).unwrap();
Ok(sig)
}
pub fn date(&mut self, year: u16, month: u8, day: u8) -> &mut Self {
self.date = u32::from_str_radix(&format!("{:04}{:02}{:02}", year, month, day), 16).unwrap();
self
}
pub fn swdefined(&mut self, swdefined: u32) -> &mut Self {
self.swdefined = swdefined;
self
}
pub fn isvprodid(&mut self, isvprodid: u16) -> &mut Self {
self.isvprodid = isvprodid;
self
}
pub fn isvsvn(&mut self, isvsvn: u16) -> &mut Self {
self.isvsvn = isvsvn;
self
}
pub fn miscselect(&mut self, miscselect: Miscselect, mask: u32) -> &mut Self {
self.miscselect = miscselect;
self.miscmask = mask;
self
}
pub fn attributes_flags(&mut self, flags: AttributesFlags, mask: u64) -> &mut Self {
self.attributes.flags = flags;
self.attributemask[0] = mask;
self
}
pub fn attributes_xfrm(&mut self, xfrm: u64, mask: u64) -> &mut Self {
self.attributes.xfrm = xfrm;
self.attributemask[1] = mask;
self
}
pub fn enclavehash(&mut self, hash: EnclaveHash) -> &mut Self {
self.enclavehash = hash;
self
}
}
pub fn read<R: Read>(reader: &mut R) -> IoResult<Sigstruct> {
let mut buf = [0u8; 1808];
reader.read_exact(&mut buf)?;
Sigstruct::try_copy_from(&buf).ok_or_else(|| unreachable!())
}
#[cfg(test)]
mod tests {
use super::{EnclaveHash, Signer};
#[test]
fn signer() {
let signer = Signer::new(EnclaveHash::new([0; 32]));
assert!(signer.date & 0xff <= 0x31); assert!(signer.date & 0xff00 <= 0x1200); assert!(signer.date & 0xffff0000 >= 0x20240000); assert!(signer.date & 0xffff0000 <= 0x20500000);
}
}