Skip to content

Commit

Permalink
wip: update presentation
Browse files Browse the repository at this point in the history
Signed-off-by: Ryan Tate <[email protected]>
  • Loading branch information
Ryanmtate committed Nov 19, 2024
1 parent be54eb2 commit 5a606b5
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 24 deletions.
16 changes: 16 additions & 0 deletions src/definitions/helpers/non_empty_vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,22 @@ impl<T: Clone> NonEmptyVec<T> {
}
}

impl<T: Clone> NonEmptyVec<T> {
pub fn try_from_iter<I: IntoIterator<Item = T>>(iter: I) -> Result<Self, Error> {
let mut v = Vec::new();
let mut iter = iter.into_iter();
if let Some(t) = iter.next() {
v.push(t);
} else {
return Err(Error::Empty);
}
for t in iter {
v.push(t);
}
Ok(NonEmptyVec(v))
}
}

impl<T: Clone> TryFrom<Vec<T>> for NonEmptyVec<T> {
type Error = Error;

Expand Down
21 changes: 20 additions & 1 deletion src/definitions/x509/x5chain.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::definitions::helpers::non_empty_vec;
use crate::definitions::helpers::NonEmptyVec;
use crate::definitions::x509::error::Error as X509Error;
use crate::definitions::x509::trust_anchor::check_validity_period;
Expand Down Expand Up @@ -77,6 +78,22 @@ impl From<NonEmptyVec<X509>> for X5Chain {
}
}

impl TryFrom<Vec<X509>> for X5Chain {
type Error = non_empty_vec::Error;

fn try_from(v: Vec<X509>) -> Result<Self, Self::Error> {
NonEmptyVec::try_from_iter(v.into_iter()).map(Self)
}
}

impl TryFrom<Vec<Vec<u8>>> for X5Chain {
type Error = non_empty_vec::Error;

fn try_from(v: Vec<Vec<u8>>) -> Result<Self, Self::Error> {
NonEmptyVec::try_from_iter(v.into_iter().map(|bytes| X509 { bytes })).map(Self)
}
}

impl X5Chain {
pub fn builder() -> Builder {
Builder::default()
Expand Down Expand Up @@ -124,7 +141,9 @@ impl X5Chain {
}
}

pub fn get_signer_key(&self) -> Result<VerifyingKey, X509Error> {
/// Returns the first certificate in the x.509 certificate chain,
/// which is expected be the reader's certificate.
pub fn get_public_key(&self) -> Result<VerifyingKey, X509Error> {
let leaf = self.0.first().ok_or(X509Error::CborDecodingError)?;
leaf.public_key().map(|key| key.into())
}
Expand Down
2 changes: 1 addition & 1 deletion src/presentation/mdoc_auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use ssi_jwk::Params;
use ssi_jwk::JWK as SsiJwk;

pub fn issuer_authentication(x5chain: X5Chain, issuer_signed: &IssuerSigned) -> Result<(), Error> {
let signer_key = x5chain.get_signer_key()?;
let signer_key = x5chain.get_public_key()?;
let verification_result: cose::sign1::VerificationResult =
issuer_signed
.issuer_auth
Expand Down
2 changes: 1 addition & 1 deletion src/presentation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ pub trait Stringify: Serialize + for<'a> Deserialize<'a> {

/// Deserialize the object from the [CBOR](https://cbor.io) representation.
///
/// You can call this on something returned by [Stringify::stringify].
/// You can call this on something returned by [Stringify::stringify].
/// Operation may fail, so it returns a [Result].
///
/// # Example
Expand Down
43 changes: 23 additions & 20 deletions src/presentation/reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,18 +36,14 @@ use crate::{
},
definitions::{DeviceEngagement, DeviceResponse, SessionData, SessionTranscript180135},
};
use aes::cipher::{generic_array::GenericArray, typenum::U32};
use anyhow::{anyhow, Result};
use coset::{CoseSign1Builder, Header, Label};
// use cose_rs::algorithm::Algorithm;
// use cose_rs::sign1::HeaderMap;
// use cose_rs::CoseSign1;
use p256::ecdsa::SigningKey;
use sec1::DecodeEcPrivateKey;
use serde::{Deserialize, Serialize};
use serde_json::json;
use serde_json::Value;
use std::collections::BTreeMap;
use std::future::Future;
use std::pin::Pin;
use uuid::Uuid;

/// The main state of the reader.
Expand All @@ -64,7 +60,6 @@ pub struct SessionManager {
sk_reader: [u8; 32],
reader_message_counter: u32,
trust_anchor_registry: Option<TrustAnchorRegistry>,
reader_auth_key: [u8; 32],
reader_x5chain: X5Chain,
}

Expand Down Expand Up @@ -185,12 +180,12 @@ impl SessionManager {
/// Internally it generates the ephemeral keys,
/// derives the shared secret, and derives the session keys
/// (using **Diffie–Hellman key exchange**).
pub fn establish_session(
pub async fn establish_session(
qr_code: String,
namespaces: device_request::Namespaces,
trust_anchor_registry: Option<TrustAnchorRegistry>,
reader_x5chain: X5Chain,
reader_key: &str,
reader_signer: impl FnOnce(Vec<u8>) -> Pin<Box<dyn Future<Output = Result<Vec<u8>>> + Send>>,
) -> Result<(Self, Vec<u8>, [u8; 16])> {
let device_engagement_bytes =
Tag24::<DeviceEngagement>::from_qr_code_uri(&qr_code).map_err(|e| anyhow!(e))?;
Expand Down Expand Up @@ -226,21 +221,21 @@ impl SessionManager {
let sk_device =
derive_session_key(&shared_secret, &session_transcript_bytes, false)?.into();

let reader_signing_key: SigningKey = ecdsa::SigningKey::from_sec1_pem(reader_key)?;
let reader_auth_key: GenericArray<u8, U32> = reader_signing_key.to_bytes();

let mut session_manager = Self {
session_transcript,
sk_device,
device_message_counter: 0,
sk_reader,
reader_message_counter: 0,
trust_anchor_registry,
reader_auth_key: reader_auth_key.into(),
// reader_auth_key: reader_auth_key.into(),
reader_x5chain,
};

let request = session_manager.build_request(namespaces)?;
let request = session_manager
.build_request(namespaces, reader_signer)
.await?;

let session = SessionEstablishment {
data: request.into(),
e_reader_key: e_reader_key_public,
Expand Down Expand Up @@ -270,16 +265,24 @@ impl SessionManager {
}

/// Creates a new request with specified elements to request.
pub fn new_request(&mut self, namespaces: device_request::Namespaces) -> Result<Vec<u8>> {
let request = self.build_request(namespaces)?;
pub async fn new_request(
&mut self,
namespaces: device_request::Namespaces,
reader_signer: impl FnOnce(Vec<u8>) -> Pin<Box<dyn Future<Output = Result<Vec<u8>>> + Send>>,
) -> Result<Vec<u8>> {
let request = self.build_request(namespaces, reader_signer).await?;
let session = SessionData {
data: Some(request.into()),
status: None,
};
cbor::to_vec(&session).map_err(Into::into)
}

fn build_request(&mut self, namespaces: device_request::Namespaces) -> Result<Vec<u8>> {
async fn build_request(
&mut self,
namespaces: device_request::Namespaces,
reader_signer: impl FnOnce(Vec<u8>) -> Pin<Box<dyn Future<Output = Result<Vec<u8>>> + Send>>,
) -> Result<Vec<u8>> {
// if !validate_request(namespaces.clone()).is_ok() {
// return Err(anyhow::Error::msg(
// "At least one of the namespaces contain an invalid combination of fields to request",
Expand All @@ -305,12 +308,12 @@ impl SessionManager {
Tag24::new(items_request.clone())?,
);

let reader_signing_key = SigningKey::from_slice(&self.reader_auth_key)?; //SigningKey::from_bytes(self.reader_auth_key.to_vec());
let signature = reader_signing_key.sign_recoverable(&cbor::to_vec(&payload)?)?;
let signature = reader_signer(cbor::to_vec(&payload)?).await?;

let cose_sign1 = CoseSign1Builder::new()
.unprotected(header_map)
.payload(cbor::to_vec(&payload)?)
.signature(signature.0.to_vec())
.signature(signature)
.build();

let doc_request = DocRequest {
Expand Down
2 changes: 1 addition & 1 deletion tests/simulated_device_and_reader_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ fn establish_reader_session(qr: String) -> Result<(reader::SessionManager, Vec<u
NAMESPACE.into(),
DataElements::new(AGE_OVER_21_ELEMENT.to_string(), false),
);
let trust_anchor_registry = None; // Option<TrustAnchorRegistry>,;
let trust_anchor_registry = None; // Option<TrustAnchorRegistry>;
let reader_x5chain = X5Chain::builder()
.with_der(include_bytes!("../test/issuance/256-cert.der"))?
.build()?;
Expand Down

0 comments on commit 5a606b5

Please sign in to comment.