use crate::cbor;
use crate::cose;
use crate::cose::sign1::VerificationResult;
use crate::definitions::device_response::Document;
use crate::definitions::issuer_signed;
use crate::definitions::session::SessionTranscript;
use crate::definitions::x509::X5Chain;
use crate::definitions::DeviceAuth;
use crate::definitions::Mso;
use crate::definitions::{device_signed::DeviceAuthentication, helpers::Tag24};
use crate::presentation::reader::Error;
use anyhow::Result;
use elliptic_curve::generic_array::GenericArray;
use issuer_signed::IssuerSigned;
use p256::ecdsa::Signature;
use p256::ecdsa::VerifyingKey;
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
.end_entity_public_key()
.map_err(Error::IssuerPublicKey)?;
let verification_result: cose::sign1::VerificationResult =
issuer_signed
.issuer_auth
.verify::<VerifyingKey, Signature>(&signer_key, None, None);
verification_result
.into_result()
.map_err(Error::IssuerAuthentication)
}
pub fn device_authentication<S>(document: &Document, session_transcript: S) -> Result<(), Error>
where
S: SessionTranscript + Clone,
{
let mso_bytes = document
.issuer_signed
.issuer_auth
.payload
.as_ref()
.ok_or(Error::DetachedIssuerAuth)?;
let mso: Tag24<Mso> = cbor::from_slice(mso_bytes).map_err(|_| Error::MSOParsing)?;
let device_key = mso.into_inner().device_key_info.device_key;
let jwk = SsiJwk::try_from(device_key)?;
match jwk.params {
Params::EC(p) => {
let x_coordinate = p.x_coordinate.clone();
let y_coordinate = p.y_coordinate.clone();
let (Some(x), Some(y)) = (x_coordinate, y_coordinate) else {
return Err(Error::MdocAuth(
"device key jwk is missing coordinates".to_string(),
));
};
let encoded_point = p256::EncodedPoint::from_affine_coordinates(
GenericArray::from_slice(x.0.as_slice()),
GenericArray::from_slice(y.0.as_slice()),
false,
);
let verifying_key = VerifyingKey::from_encoded_point(&encoded_point)?;
let namespaces_bytes = &document.device_signed.namespaces;
let device_auth: &DeviceAuth = &document.device_signed.device_auth;
match device_auth {
DeviceAuth::DeviceSignature(device_signature) => {
let detached_payload = Tag24::new(DeviceAuthentication::new(
session_transcript,
document.doc_type.clone(),
namespaces_bytes.clone(),
))
.map_err(|_| Error::CborDecodingError)?;
let external_aad = None;
let cbor_payload = cbor::to_vec(&detached_payload)?;
let result = device_signature.verify::<VerifyingKey, Signature>(
&verifying_key,
Some(&cbor_payload),
external_aad,
);
match result {
VerificationResult::Success => Ok(()),
VerificationResult::Failure(e) => Err(Error::MdocAuth(format!(
"failed verifying device signature: {e}"
))),
VerificationResult::Error(e) => Err(Error::MdocAuth(format!(
"error verifying device signature: {e}"
))),
}
}
DeviceAuth::DeviceMac(_) => {
Err(Error::Unsupported)
}
}
}
_ => Err(Error::MdocAuth("Unsupported device_key type".to_string())),
}
}