Strip out the Policy components into a separate crate
Signed-off-by: Patrick Uiterwijk <patrick@puiterwijk.org>
This commit is contained in:
parent
76e880d806
commit
cac6aacde4
|
@ -13,3 +13,4 @@ biscuit = "0.5.0-beta2"
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
base64 = "0.12.1"
|
base64 = "0.12.1"
|
||||||
atty = "0.2.14"
|
atty = "0.2.14"
|
||||||
|
tpm2-policy = "0.1.0"
|
||||||
|
|
546
src/main.rs
546
src/main.rs
|
@ -12,7 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use std::convert::{TryFrom, TryInto};
|
use std::convert::TryFrom;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
@ -38,14 +38,16 @@ use tss_esapi::Context;
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
pub fn serialize_as_base64_url_no_pad<S>(bytes: &[u8], serializer: S) -> Result<S::Ok, S::Error>
|
use tpm2_policy::{TPMPolicyStep, SignedPolicyList, PublicKey};
|
||||||
|
|
||||||
|
fn serialize_as_base64_url_no_pad<S>(bytes: &[u8], serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
S: serde::Serializer,
|
S: serde::Serializer,
|
||||||
{
|
{
|
||||||
serializer.serialize_str(&base64::encode_config(bytes, base64::URL_SAFE_NO_PAD))
|
serializer.serialize_str(&base64::encode_config(bytes, base64::URL_SAFE_NO_PAD))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deserialize_as_base64_url_no_pad<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
|
fn deserialize_as_base64_url_no_pad<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
|
||||||
where
|
where
|
||||||
D: serde::Deserializer<'de>,
|
D: serde::Deserializer<'de>,
|
||||||
{
|
{
|
||||||
|
@ -54,21 +56,6 @@ where
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn serialize_as_base64<S>(bytes: &[u8], serializer: S) -> Result<S::Ok, S::Error>
|
|
||||||
where
|
|
||||||
S: serde::Serializer,
|
|
||||||
{
|
|
||||||
serializer.serialize_str(&base64::encode(bytes))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn deserialize_as_base64<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
|
|
||||||
where
|
|
||||||
D: serde::Deserializer<'de>,
|
|
||||||
{
|
|
||||||
String::deserialize(deserializer)
|
|
||||||
.and_then(|string| base64::decode(&string).map_err(serde::de::Error::custom))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn tpm_sym_def(_ctx: &mut tss_esapi::Context) -> Result<tss_esapi::tss2_esys::TPMT_SYM_DEF, PinError> {
|
fn tpm_sym_def(_ctx: &mut tss_esapi::Context) -> Result<tss_esapi::tss2_esys::TPMT_SYM_DEF, PinError> {
|
||||||
Ok(tss_esapi::tss2_esys::TPMT_SYM_DEF {
|
Ok(tss_esapi::tss2_esys::TPMT_SYM_DEF {
|
||||||
algorithm: tss_esapi::constants::TPM2_ALG_AES,
|
algorithm: tss_esapi::constants::TPM2_ALG_AES,
|
||||||
|
@ -87,6 +74,7 @@ enum PinError {
|
||||||
JWE(biscuit::errors::Error),
|
JWE(biscuit::errors::Error),
|
||||||
Base64Decoding(base64::DecodeError),
|
Base64Decoding(base64::DecodeError),
|
||||||
Utf8(std::str::Utf8Error),
|
Utf8(std::str::Utf8Error),
|
||||||
|
PolicyError(tpm2_policy::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PinError {}
|
impl PinError {}
|
||||||
|
@ -120,12 +108,28 @@ impl fmt::Display for PinError {
|
||||||
err.fmt(f)
|
err.fmt(f)
|
||||||
}
|
}
|
||||||
PinError::NoCommand => write!(f, "No command provided"),
|
PinError::NoCommand => write!(f, "No command provided"),
|
||||||
|
PinError::PolicyError(err) => {
|
||||||
|
write!(f, "Policy Error: ")?;
|
||||||
|
err.fmt(f)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Error for PinError {}
|
impl Error for PinError {}
|
||||||
|
|
||||||
|
impl From<std::io::Error> for PinError {
|
||||||
|
fn from(err: std::io::Error) -> Self {
|
||||||
|
PinError::IO(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<tpm2_policy::Error> for PinError {
|
||||||
|
fn from(err: tpm2_policy::Error) -> Self {
|
||||||
|
PinError::PolicyError(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<&'static str> for PinError {
|
impl From<&'static str> for PinError {
|
||||||
fn from(err: &'static str) -> Self {
|
fn from(err: &'static str) -> Self {
|
||||||
PinError::Text(err)
|
PinError::Text(err)
|
||||||
|
@ -138,12 +142,6 @@ impl From<serde_json::Error> for PinError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<std::io::Error> for PinError {
|
|
||||||
fn from(err: std::io::Error) -> Self {
|
|
||||||
PinError::IO(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<tss_esapi::response_code::Error> for PinError {
|
impl From<tss_esapi::response_code::Error> for PinError {
|
||||||
fn from(err: tss_esapi::response_code::Error) -> Self {
|
fn from(err: tss_esapi::response_code::Error) -> Self {
|
||||||
PinError::TPM(err)
|
PinError::TPM(err)
|
||||||
|
@ -168,23 +166,6 @@ impl From<std::str::Utf8Error> for PinError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
enum TPMPolicyStep {
|
|
||||||
NoStep,
|
|
||||||
PCRs(
|
|
||||||
tss_esapi::utils::algorithm_specifiers::HashingAlgorithm,
|
|
||||||
Vec<u64>,
|
|
||||||
Box<TPMPolicyStep>,
|
|
||||||
),
|
|
||||||
Authorized {
|
|
||||||
signkey: PublicKey,
|
|
||||||
policy_ref: Vec<u8>,
|
|
||||||
policies: Option<SignedPolicyList>,
|
|
||||||
next: Box<TPMPolicyStep>,
|
|
||||||
},
|
|
||||||
Or([Box<TPMPolicyStep>; 8]),
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_and_set_tpm2_session(
|
fn create_and_set_tpm2_session(
|
||||||
ctx: &mut tss_esapi::Context,
|
ctx: &mut tss_esapi::Context,
|
||||||
session_type: tss_esapi::tss2_esys::TPM2_SE,
|
session_type: tss_esapi::tss2_esys::TPM2_SE,
|
||||||
|
@ -199,7 +180,7 @@ fn create_and_set_tpm2_session(
|
||||||
symdef,
|
symdef,
|
||||||
tss_esapi::constants::TPM2_ALG_SHA256,
|
tss_esapi::constants::TPM2_ALG_SHA256,
|
||||||
)?;
|
)?;
|
||||||
let session_attr = utils::TpmaSessionBuilder::new()
|
let session_attr = tss_esapi::utils::TpmaSessionBuilder::new()
|
||||||
.with_flag(tss_esapi::constants::TPMA_SESSION_DECRYPT)
|
.with_flag(tss_esapi::constants::TPMA_SESSION_DECRYPT)
|
||||||
.with_flag(tss_esapi::constants::TPMA_SESSION_ENCRYPT)
|
.with_flag(tss_esapi::constants::TPMA_SESSION_ENCRYPT)
|
||||||
.build();
|
.build();
|
||||||
|
@ -211,275 +192,6 @@ fn create_and_set_tpm2_session(
|
||||||
Ok(session)
|
Ok(session)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TPMPolicyStep {
|
|
||||||
/// Sends the generate policy to the TPM2, and sets the authorized policy as active
|
|
||||||
/// Returns the policy_digest for authInfo
|
|
||||||
fn send_policy(
|
|
||||||
self,
|
|
||||||
ctx: &mut tss_esapi::Context,
|
|
||||||
trial_policy: bool,
|
|
||||||
) -> Result<Option<tss_esapi::utils::Digest>, PinError> {
|
|
||||||
let pol_type = if trial_policy {
|
|
||||||
tss_esapi::constants::TPM2_SE_TRIAL
|
|
||||||
} else {
|
|
||||||
tss_esapi::constants::TPM2_SE_POLICY
|
|
||||||
};
|
|
||||||
|
|
||||||
let symdef = tpm_sym_def(ctx)?;
|
|
||||||
|
|
||||||
let session = ctx.start_auth_session(
|
|
||||||
ESYS_TR_NONE,
|
|
||||||
ESYS_TR_NONE,
|
|
||||||
&[],
|
|
||||||
pol_type,
|
|
||||||
symdef,
|
|
||||||
tss_esapi::constants::TPM2_ALG_SHA256,
|
|
||||||
)?;
|
|
||||||
let session_attr = utils::TpmaSessionBuilder::new()
|
|
||||||
.with_flag(tss_esapi::constants::TPMA_SESSION_DECRYPT)
|
|
||||||
.with_flag(tss_esapi::constants::TPMA_SESSION_ENCRYPT)
|
|
||||||
.build();
|
|
||||||
ctx.tr_sess_set_attributes(session, session_attr)?;
|
|
||||||
|
|
||||||
match self {
|
|
||||||
TPMPolicyStep::NoStep => {
|
|
||||||
create_and_set_tpm2_session(ctx, tss_esapi::constants::TPM2_SE_HMAC)?;
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
self._send_policy(ctx, session)?;
|
|
||||||
|
|
||||||
let pol_digest = ctx.policy_get_digest(session)?;
|
|
||||||
|
|
||||||
if trial_policy {
|
|
||||||
create_and_set_tpm2_session(ctx, tss_esapi::constants::TPM2_SE_HMAC)?;
|
|
||||||
} else {
|
|
||||||
ctx.set_sessions((session, ESYS_TR_NONE, ESYS_TR_NONE));
|
|
||||||
}
|
|
||||||
Ok(Some(pol_digest))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn _send_policy(
|
|
||||||
self,
|
|
||||||
ctx: &mut tss_esapi::Context,
|
|
||||||
policy_session: tss_esapi::tss2_esys::ESYS_TR,
|
|
||||||
) -> Result<(), PinError> {
|
|
||||||
match self {
|
|
||||||
TPMPolicyStep::NoStep => Ok(()),
|
|
||||||
|
|
||||||
TPMPolicyStep::PCRs(pcr_hash_alg, pcr_ids, next) => {
|
|
||||||
let pcr_ids: Result<Vec<tss_esapi::utils::PcrSlot>, PinError> =
|
|
||||||
pcr_ids.iter().map(|x| pcr_id_to_slot(x)).collect();
|
|
||||||
let pcr_ids: Vec<tss_esapi::utils::PcrSlot> = pcr_ids?;
|
|
||||||
|
|
||||||
let pcr_sel = tss_esapi::utils::PcrSelectionsBuilder::new()
|
|
||||||
.with_selection(pcr_hash_alg, &pcr_ids)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
// Ensure PCR reading occurs with no sessions (we don't use audit sessions)
|
|
||||||
let old_ses = ctx.sessions();
|
|
||||||
ctx.set_sessions((ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE));
|
|
||||||
let (_update_counter, pcr_sel, pcr_data) = ctx.pcr_read(pcr_sel)?;
|
|
||||||
ctx.set_sessions(old_ses);
|
|
||||||
|
|
||||||
let concatenated_pcr_values: Vec<&[u8]> = pcr_ids
|
|
||||||
.iter()
|
|
||||||
.map(|x| {
|
|
||||||
pcr_data
|
|
||||||
.pcr_bank(pcr_hash_alg)
|
|
||||||
.unwrap()
|
|
||||||
.pcr_value(*x)
|
|
||||||
.unwrap()
|
|
||||||
.value()
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
let concatenated_pcr_values = concatenated_pcr_values.as_slice().concat();
|
|
||||||
|
|
||||||
let (hashed_data, _ticket) = ctx.hash(
|
|
||||||
&concatenated_pcr_values,
|
|
||||||
tss_esapi::utils::algorithm_specifiers::HashingAlgorithm::Sha256,
|
|
||||||
tss_esapi::utils::Hierarchy::Owner,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
ctx.policy_pcr(policy_session, &hashed_data, pcr_sel)?;
|
|
||||||
next._send_policy(ctx, policy_session)
|
|
||||||
}
|
|
||||||
|
|
||||||
TPMPolicyStep::Authorized {
|
|
||||||
signkey,
|
|
||||||
policy_ref,
|
|
||||||
policies,
|
|
||||||
next,
|
|
||||||
} => {
|
|
||||||
let policy_ref = tss_esapi::utils::Digest::try_from(policy_ref)?;
|
|
||||||
|
|
||||||
let tpm_signkey = tss_esapi::tss2_esys::TPM2B_PUBLIC::try_from(&signkey)?;
|
|
||||||
let loaded_key =
|
|
||||||
ctx.load_external_public(&tpm_signkey, tss_esapi::utils::Hierarchy::Owner)?;
|
|
||||||
let loaded_key_name = ctx.tr_get_name(loaded_key)?;
|
|
||||||
|
|
||||||
let (approved_policy, check_ticket) = match policies {
|
|
||||||
None => {
|
|
||||||
/* Some TPMs don't seem to like the Null ticket.. Let's just use a dummy
|
|
||||||
let null_ticket = tss_esapi::tss2_esys::TPMT_TK_VERIFIED {
|
|
||||||
tag: tss_esapi::constants::TPM2_ST_VERIFIED,
|
|
||||||
hierarchy: tss_esapi::tss2_esys::ESYS_TR_RH_NULL,
|
|
||||||
digest: tss_esapi::tss2_esys::TPM2B_DIGEST {
|
|
||||||
size: 32,
|
|
||||||
buffer: [0; 64],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
*/
|
|
||||||
let dummy_ticket = get_dummy_ticket(ctx);
|
|
||||||
(tss_esapi::utils::Digest::try_from(vec![])?, dummy_ticket)
|
|
||||||
}
|
|
||||||
Some(policies) => find_and_play_applicable_policy(
|
|
||||||
ctx,
|
|
||||||
&policies,
|
|
||||||
policy_session,
|
|
||||||
policy_ref.value(),
|
|
||||||
signkey.get_signing_scheme(),
|
|
||||||
loaded_key,
|
|
||||||
)?,
|
|
||||||
};
|
|
||||||
|
|
||||||
ctx.policy_authorize(
|
|
||||||
policy_session,
|
|
||||||
approved_policy,
|
|
||||||
tss_esapi::tss2_esys::TPM2B_DIGEST::try_from(policy_ref)?,
|
|
||||||
loaded_key_name,
|
|
||||||
check_ticket,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
next._send_policy(ctx, policy_session)
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => Err(PinError::Text("Policy not implemented")),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find_and_play_applicable_policy(
|
|
||||||
ctx: &mut tss_esapi::Context,
|
|
||||||
policies: &[SignedPolicy],
|
|
||||||
policy_session: ESYS_TR,
|
|
||||||
policy_ref: &[u8],
|
|
||||||
scheme: utils::AsymSchemeUnion,
|
|
||||||
loaded_key: ESYS_TR,
|
|
||||||
) -> Result<
|
|
||||||
(
|
|
||||||
tss_esapi::utils::Digest,
|
|
||||||
tss_esapi::tss2_esys::TPMT_TK_VERIFIED,
|
|
||||||
),
|
|
||||||
PinError,
|
|
||||||
> {
|
|
||||||
for policy in policies {
|
|
||||||
if policy.policy_ref != policy_ref {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(policy_digest) = play_policy(ctx, &policy, policy_session)? {
|
|
||||||
// aHash ≔ H_{aHashAlg}(approvedPolicy || policyRef)
|
|
||||||
let mut ahash = Vec::new();
|
|
||||||
ahash.write_all(&policy_digest)?;
|
|
||||||
ahash.write_all(&policy_ref)?;
|
|
||||||
|
|
||||||
let ahash = ctx
|
|
||||||
.hash(
|
|
||||||
&ahash,
|
|
||||||
tss_esapi::utils::algorithm_specifiers::HashingAlgorithm::Sha256,
|
|
||||||
tss_esapi::utils::Hierarchy::Null,
|
|
||||||
)?
|
|
||||||
.0;
|
|
||||||
let signature = tss_esapi::utils::Signature {
|
|
||||||
scheme,
|
|
||||||
signature: tss_esapi::utils::SignatureData::RsaSignature(policy.signature.clone()),
|
|
||||||
};
|
|
||||||
let tkt = ctx.verify_signature(loaded_key, &ahash, &signature.try_into()?)?;
|
|
||||||
|
|
||||||
return Ok((policy_digest, tkt));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Err(PinError::Text("No matching authorized policy found"))
|
|
||||||
}
|
|
||||||
|
|
||||||
// This function would do a simple check whether the policy has a chance for success.
|
|
||||||
// It does explicitly not change policy_session
|
|
||||||
fn check_policy_feasibility(_ctx: &mut tss_esapi::Context, _policy: &SignedPolicy) -> Result<bool,PinError> {
|
|
||||||
Ok(true)
|
|
||||||
// TODO: Implement this, to check whether the PCRs in this branch would match
|
|
||||||
}
|
|
||||||
|
|
||||||
fn play_policy(
|
|
||||||
ctx: &mut tss_esapi::Context,
|
|
||||||
policy: &SignedPolicy,
|
|
||||||
policy_session: ESYS_TR,
|
|
||||||
) -> Result<Option<tss_esapi::utils::Digest>, PinError> {
|
|
||||||
if !check_policy_feasibility(ctx, policy)? {
|
|
||||||
return Ok(None)
|
|
||||||
}
|
|
||||||
|
|
||||||
for step in &policy.steps {
|
|
||||||
let tpmstep = TPMPolicyStep::try_from(step)?;
|
|
||||||
tpmstep._send_policy(ctx, policy_session)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Some(ctx.policy_get_digest(policy_session)?))
|
|
||||||
}
|
|
||||||
|
|
||||||
// It turns out that a Null ticket does not work for some TPMs, so let's just generate
|
|
||||||
// a dummy ticket. This is a valid ticket, but over a totally useless piece of data.
|
|
||||||
fn get_dummy_ticket(context: &mut tss_esapi::Context) -> tss_esapi::tss2_esys::TPMT_TK_VERIFIED {
|
|
||||||
let old_ses = context.sessions();
|
|
||||||
context.set_sessions((ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE));
|
|
||||||
create_and_set_tpm2_session(context, tss_esapi::constants::TPM2_SE_HMAC).unwrap();
|
|
||||||
|
|
||||||
let signing_key_pub = utils::create_unrestricted_signing_rsa_public(
|
|
||||||
tss_esapi::utils::AsymSchemeUnion::RSASSA(
|
|
||||||
tss_esapi::utils::algorithm_specifiers::HashingAlgorithm::Sha256,
|
|
||||||
),
|
|
||||||
2048,
|
|
||||||
0,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let key_handle = context
|
|
||||||
.create_primary_key(ESYS_TR_RH_OWNER, &signing_key_pub, &[], &[], &[], &[])
|
|
||||||
.unwrap();
|
|
||||||
let ahash = context
|
|
||||||
.hash(
|
|
||||||
&[0x1, 0x2],
|
|
||||||
tss_esapi::utils::algorithm_specifiers::HashingAlgorithm::Sha256,
|
|
||||||
tss_esapi::utils::Hierarchy::Null,
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
.0;
|
|
||||||
|
|
||||||
let scheme = tss_esapi::tss2_esys::TPMT_SIG_SCHEME {
|
|
||||||
scheme: tss_esapi::constants::TPM2_ALG_NULL,
|
|
||||||
details: Default::default(),
|
|
||||||
};
|
|
||||||
let validation = tss_esapi::tss2_esys::TPMT_TK_HASHCHECK {
|
|
||||||
tag: tss_esapi::constants::TPM2_ST_HASHCHECK,
|
|
||||||
hierarchy: tss_esapi::constants::TPM2_RH_NULL,
|
|
||||||
digest: Default::default(),
|
|
||||||
};
|
|
||||||
// A signature over just the policy_digest, since the policy_ref is empty
|
|
||||||
let signature = context
|
|
||||||
.sign(key_handle, &ahash, scheme, &validation)
|
|
||||||
.unwrap();
|
|
||||||
let tkt = context
|
|
||||||
.verify_signature(key_handle, &ahash, &signature.try_into().unwrap())
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
context.set_sessions(old_ses);
|
|
||||||
|
|
||||||
tkt
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, std::fmt::Debug)]
|
#[derive(Serialize, Deserialize, std::fmt::Debug)]
|
||||||
struct TPM2Config {
|
struct TPM2Config {
|
||||||
hash: Option<String>,
|
hash: Option<String>,
|
||||||
|
@ -525,22 +237,6 @@ fn get_authorized_policy_step(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<&SignedPolicyStep> for TPMPolicyStep {
|
|
||||||
type Error = PinError;
|
|
||||||
|
|
||||||
fn try_from(spolicy: &SignedPolicyStep) -> Result<Self, PinError> {
|
|
||||||
match spolicy {
|
|
||||||
SignedPolicyStep::PCRs{pcr_ids, hash_algorithm, value: _} => {
|
|
||||||
Ok(TPMPolicyStep::PCRs(
|
|
||||||
get_pcr_hash_alg_from_name(Some(&hash_algorithm)),
|
|
||||||
pcr_ids.iter().map(|x| *x as u64).collect(),
|
|
||||||
Box::new(TPMPolicyStep::NoStep),
|
|
||||||
))
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryFrom<&TPM2Config> for TPMPolicyStep {
|
impl TryFrom<&TPM2Config> for TPMPolicyStep {
|
||||||
type Error = PinError;
|
type Error = PinError;
|
||||||
|
|
||||||
|
@ -582,36 +278,6 @@ impl TryFrom<&TPM2Config> for TPMPolicyStep {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pcr_id_to_slot(pcr: &u64) -> Result<tss_esapi::utils::PcrSlot, PinError> {
|
|
||||||
match pcr {
|
|
||||||
0 => Ok(tss_esapi::utils::PcrSlot::Slot0),
|
|
||||||
1 => Ok(tss_esapi::utils::PcrSlot::Slot1),
|
|
||||||
2 => Ok(tss_esapi::utils::PcrSlot::Slot2),
|
|
||||||
3 => Ok(tss_esapi::utils::PcrSlot::Slot3),
|
|
||||||
4 => Ok(tss_esapi::utils::PcrSlot::Slot4),
|
|
||||||
5 => Ok(tss_esapi::utils::PcrSlot::Slot5),
|
|
||||||
6 => Ok(tss_esapi::utils::PcrSlot::Slot6),
|
|
||||||
7 => Ok(tss_esapi::utils::PcrSlot::Slot7),
|
|
||||||
8 => Ok(tss_esapi::utils::PcrSlot::Slot8),
|
|
||||||
9 => Ok(tss_esapi::utils::PcrSlot::Slot9),
|
|
||||||
10 => Ok(tss_esapi::utils::PcrSlot::Slot10),
|
|
||||||
11 => Ok(tss_esapi::utils::PcrSlot::Slot11),
|
|
||||||
12 => Ok(tss_esapi::utils::PcrSlot::Slot12),
|
|
||||||
13 => Ok(tss_esapi::utils::PcrSlot::Slot13),
|
|
||||||
14 => Ok(tss_esapi::utils::PcrSlot::Slot14),
|
|
||||||
15 => Ok(tss_esapi::utils::PcrSlot::Slot15),
|
|
||||||
16 => Ok(tss_esapi::utils::PcrSlot::Slot16),
|
|
||||||
17 => Ok(tss_esapi::utils::PcrSlot::Slot17),
|
|
||||||
18 => Ok(tss_esapi::utils::PcrSlot::Slot18),
|
|
||||||
19 => Ok(tss_esapi::utils::PcrSlot::Slot19),
|
|
||||||
20 => Ok(tss_esapi::utils::PcrSlot::Slot20),
|
|
||||||
21 => Ok(tss_esapi::utils::PcrSlot::Slot21),
|
|
||||||
22 => Ok(tss_esapi::utils::PcrSlot::Slot22),
|
|
||||||
23 => Ok(tss_esapi::utils::PcrSlot::Slot23),
|
|
||||||
_ => Err(PinError::Text("Invalid PCR slot requested")),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_pcr_hash_alg_from_name(
|
fn get_pcr_hash_alg_from_name(
|
||||||
name: Option<&String>,
|
name: Option<&String>,
|
||||||
) -> tss_esapi::utils::algorithm_specifiers::HashingAlgorithm {
|
) -> tss_esapi::utils::algorithm_specifiers::HashingAlgorithm {
|
||||||
|
@ -1096,172 +762,6 @@ fn get_key_public(key_type: &str) -> Result<tss_esapi::tss2_esys::TPM2B_PUBLIC,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
|
||||||
enum SignedPolicyStep {
|
|
||||||
PCRs {
|
|
||||||
pcr_ids: Vec<u16>,
|
|
||||||
hash_algorithm: String,
|
|
||||||
#[serde(
|
|
||||||
deserialize_with = "deserialize_as_base64",
|
|
||||||
serialize_with = "serialize_as_base64"
|
|
||||||
)]
|
|
||||||
value: Vec<u8>,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
|
||||||
struct SignedPolicy {
|
|
||||||
// policy_ref contains the policy_ref used in the aHash, used to determine the policy to use from a list
|
|
||||||
#[serde(
|
|
||||||
deserialize_with = "deserialize_as_base64",
|
|
||||||
serialize_with = "serialize_as_base64"
|
|
||||||
)]
|
|
||||||
policy_ref: Vec<u8>,
|
|
||||||
// steps contains the policy steps that are signed
|
|
||||||
steps: Vec<SignedPolicyStep>,
|
|
||||||
// signature contains the signature over aHash
|
|
||||||
#[serde(
|
|
||||||
deserialize_with = "deserialize_as_base64",
|
|
||||||
serialize_with = "serialize_as_base64"
|
|
||||||
)]
|
|
||||||
signature: Vec<u8>,
|
|
||||||
}
|
|
||||||
|
|
||||||
type SignedPolicyList = Vec<SignedPolicy>;
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
|
||||||
enum RSAPublicKeyScheme {
|
|
||||||
RSAPSS,
|
|
||||||
RSASSA,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RSAPublicKeyScheme {
|
|
||||||
fn to_scheme(&self, hash_algo: &HashAlgo) -> tss_esapi::utils::AsymSchemeUnion {
|
|
||||||
match self {
|
|
||||||
RSAPublicKeyScheme::RSAPSS => {
|
|
||||||
tss_esapi::utils::AsymSchemeUnion::RSAPSS(hash_algo.into())
|
|
||||||
}
|
|
||||||
RSAPublicKeyScheme::RSASSA => {
|
|
||||||
tss_esapi::utils::AsymSchemeUnion::RSASSA(hash_algo.into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
|
||||||
pub enum HashAlgo {
|
|
||||||
SHA1,
|
|
||||||
SHA256,
|
|
||||||
SHA384,
|
|
||||||
SHA512,
|
|
||||||
SM3_256,
|
|
||||||
SHA3_256,
|
|
||||||
SHA3_384,
|
|
||||||
SHA3_512,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HashAlgo {
|
|
||||||
fn to_tpmi_alg_hash(&self) -> tss_esapi::tss2_esys::TPMI_ALG_HASH {
|
|
||||||
let alg: tss_esapi::utils::algorithm_specifiers::HashingAlgorithm = self.into();
|
|
||||||
alg.into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<&HashAlgo> for tss_esapi::utils::algorithm_specifiers::HashingAlgorithm {
|
|
||||||
fn from(halg: &HashAlgo) -> Self {
|
|
||||||
match halg {
|
|
||||||
HashAlgo::SHA1 => tss_esapi::utils::algorithm_specifiers::HashingAlgorithm::Sha1,
|
|
||||||
HashAlgo::SHA256 => tss_esapi::utils::algorithm_specifiers::HashingAlgorithm::Sha256,
|
|
||||||
HashAlgo::SHA384 => tss_esapi::utils::algorithm_specifiers::HashingAlgorithm::Sha384,
|
|
||||||
HashAlgo::SHA512 => tss_esapi::utils::algorithm_specifiers::HashingAlgorithm::Sha512,
|
|
||||||
HashAlgo::SM3_256 => tss_esapi::utils::algorithm_specifiers::HashingAlgorithm::Sm3_256,
|
|
||||||
HashAlgo::SHA3_256 => {
|
|
||||||
tss_esapi::utils::algorithm_specifiers::HashingAlgorithm::Sha3_256
|
|
||||||
}
|
|
||||||
HashAlgo::SHA3_384 => {
|
|
||||||
tss_esapi::utils::algorithm_specifiers::HashingAlgorithm::Sha3_384
|
|
||||||
}
|
|
||||||
HashAlgo::SHA3_512 => {
|
|
||||||
tss_esapi::utils::algorithm_specifiers::HashingAlgorithm::Sha3_512
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
|
||||||
enum PublicKey {
|
|
||||||
RSA {
|
|
||||||
scheme: RSAPublicKeyScheme,
|
|
||||||
hashing_algo: HashAlgo,
|
|
||||||
exponent: u32,
|
|
||||||
#[serde(
|
|
||||||
deserialize_with = "deserialize_as_base64",
|
|
||||||
serialize_with = "serialize_as_base64"
|
|
||||||
)]
|
|
||||||
modulus: Vec<u8>,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PublicKey {
|
|
||||||
fn get_signing_scheme(&self) -> tss_esapi::utils::AsymSchemeUnion {
|
|
||||||
match self {
|
|
||||||
PublicKey::RSA {
|
|
||||||
scheme,
|
|
||||||
hashing_algo,
|
|
||||||
exponent: _,
|
|
||||||
modulus: _,
|
|
||||||
} => scheme.to_scheme(hashing_algo),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryFrom<&PublicKey> for tss_esapi::tss2_esys::TPM2B_PUBLIC {
|
|
||||||
type Error = PinError;
|
|
||||||
|
|
||||||
fn try_from(publickey: &PublicKey) -> Result<Self, Self::Error> {
|
|
||||||
match publickey {
|
|
||||||
PublicKey::RSA {
|
|
||||||
scheme,
|
|
||||||
hashing_algo,
|
|
||||||
modulus,
|
|
||||||
exponent,
|
|
||||||
} => {
|
|
||||||
let mut object_attributes = tss_esapi::utils::ObjectAttributes(0);
|
|
||||||
object_attributes.set_fixed_tpm(false);
|
|
||||||
object_attributes.set_fixed_parent(false);
|
|
||||||
object_attributes.set_sensitive_data_origin(false);
|
|
||||||
object_attributes.set_user_with_auth(true);
|
|
||||||
object_attributes.set_decrypt(false);
|
|
||||||
object_attributes.set_sign_encrypt(true);
|
|
||||||
object_attributes.set_restricted(false);
|
|
||||||
|
|
||||||
let len = modulus.len();
|
|
||||||
let mut buffer = [0_u8; 512];
|
|
||||||
buffer[..len].clone_from_slice(&modulus[..len]);
|
|
||||||
let rsa_uniq = Box::new(tss_esapi::tss2_esys::TPM2B_PUBLIC_KEY_RSA {
|
|
||||||
size: len as u16,
|
|
||||||
buffer,
|
|
||||||
});
|
|
||||||
|
|
||||||
Ok(tss_esapi::utils::Tpm2BPublicBuilder::new()
|
|
||||||
.with_type(tss_esapi::constants::TPM2_ALG_RSA)
|
|
||||||
.with_name_alg(hashing_algo.to_tpmi_alg_hash())
|
|
||||||
.with_parms(tss_esapi::utils::PublicParmsUnion::RsaDetail(
|
|
||||||
tss_esapi::utils::TpmsRsaParmsBuilder::new_unrestricted_signing_key(
|
|
||||||
scheme.to_scheme(&hashing_algo),
|
|
||||||
(modulus.len() * 8) as u16,
|
|
||||||
*exponent,
|
|
||||||
)
|
|
||||||
.build()?,
|
|
||||||
))
|
|
||||||
.with_object_attributes(object_attributes)
|
|
||||||
.with_unique(tss_esapi::utils::PublicIdUnion::Rsa(rsa_uniq))
|
|
||||||
.build()?)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn perform_decrypt(input: &str) -> Result<(), PinError> {
|
fn perform_decrypt(input: &str) -> Result<(), PinError> {
|
||||||
let token = biscuit::Compact::decode(input.trim());
|
let token = biscuit::Compact::decode(input.trim());
|
||||||
let hdr: biscuit::jwe::Header<ClevisHeader> = token.part(0)?;
|
let hdr: biscuit::jwe::Header<ClevisHeader> = token.part(0)?;
|
||||||
|
|
Loading…
Reference in a new issue