#[cfg(not(feature = "std"))]
extern crate alloc;
#[cfg(not(feature = "std"))]
use alloc::sync::Arc;
#[cfg(not(feature = "std"))]
use core::marker::PhantomData;
#[cfg(feature = "std")]
use std::marker::PhantomData;
#[cfg(feature = "std")]
use std::sync::Arc;
use crate::cms::content_info::CmsVersion;
use crate::cms::enveloped_data::{EnvelopedData, OriginatorIdentifierOrKey, RecipientInfo};
use crate::cms::signed_data::{EncapsulatedContentInfo, SignedData, SignerIdentifier, SignerInfo};
use crate::constants::TIGHTBEAM_KARI_KDF_INFO;
use crate::crypto::aead::{Decryptor, KeyInit};
use crate::crypto::hash::Digest;
use crate::crypto::key::SigningKeyProvider;
use crate::crypto::profiles::{CryptoProvider, SecurityProfileDesc};
use crate::crypto::secret::Secret;
use crate::crypto::sign::elliptic_curve::sec1::{FromEncodedPoint, ModulusSize, ToEncodedPoint};
use crate::crypto::sign::elliptic_curve::{AffinePoint, Curve, CurveArithmetic, PublicKey};
use crate::crypto::sign::{EcdsaSignatureVerifier, SignatureAlgorithmIdentifier, Verifier};
use crate::crypto::x509::policy::CertificateValidation;
use crate::der::asn1::OctetString;
use crate::der::oid::AssociatedOid;
use crate::der::{Decode, Encode};
use crate::oids;
use crate::spki::AlgorithmIdentifierOwned;
use crate::spki::EncodePublicKey;
use crate::transport::handshake::attributes;
use crate::transport::handshake::error::HandshakeError;
use crate::transport::handshake::processors::TightBeamSignedDataProcessor;
use crate::transport::handshake::state::HandshakeInvariant;
use crate::transport::handshake::state::{ServerHandshakeState, ServerStateMachine};
use crate::transport::handshake::utils::{compute_transcript_digest, extract_verifying_key_from_cert, validate_state};
use crate::transport::handshake::ServerHandshakeProtocol;
use crate::transport::handshake::{HandshakeAlertHandler, HandshakeFinalization, HandshakeNegotiation};
use crate::x509::attr::Attributes;
use crate::x509::Certificate;
pub struct CmsHandshakeServer<P>
where
P: CryptoProvider,
{
state: ServerStateMachine,
server_key_provider: Arc<dyn SigningKeyProvider>,
client_cert: Option<Arc<Certificate>>,
validated_client_cert: Option<Arc<Certificate>>,
transcript_hash: Option<[u8; 32]>,
transcript_buffer: Vec<u8>,
session_key: Option<Secret<Vec<u8>>>,
supported_profiles: Vec<SecurityProfileDesc>,
selected_profile: Option<SecurityProfileDesc>,
client_validators: Option<Arc<Vec<Arc<dyn CertificateValidation>>>>,
invariants: HandshakeInvariant,
_phantom: PhantomData<P>,
}
impl<P> CmsHandshakeServer<P>
where
P: CryptoProvider + 'static,
P::Curve: Curve + CurveArithmetic,
<P::Curve as Curve>::FieldBytesSize: ModulusSize,
AffinePoint<P::Curve>: FromEncodedPoint<P::Curve> + ToEncodedPoint<P::Curve>,
P::VerifyingKey: From<PublicKey<P::Curve>> + EncodePublicKey + Verifier<P::Signature> + 'static,
P::Signature: 'static,
P::Digest: Send + 'static + AssociatedOid,
P::AeadCipher: KeyInit + 'static,
{
pub fn new(
server_key_provider: Arc<dyn SigningKeyProvider>,
client_validators: Option<Arc<Vec<Arc<dyn CertificateValidation>>>>,
) -> Self {
Self {
state: ServerStateMachine::default(),
server_key_provider,
client_cert: None,
validated_client_cert: None,
transcript_hash: None,
transcript_buffer: Vec::new(),
session_key: None,
supported_profiles: Vec::new(),
selected_profile: None,
client_validators,
invariants: { HandshakeInvariant::default() },
_phantom: PhantomData,
}
}
#[must_use]
pub fn with_transcript_hash(mut self, hash: [u8; 32]) -> Self {
self.transcript_hash = Some(hash);
let _ = self.invariants.lock_transcript();
self
}
#[must_use]
pub fn with_supported_profiles(mut self, profiles: Vec<SecurityProfileDesc>) -> Self {
self.supported_profiles = profiles;
self
}
pub fn set_client_certificate(&mut self, cert: Certificate) -> Result<(), HandshakeError> {
if let Some(existing_cert) = &self.validated_client_cert {
if existing_cert.as_ref() != &cert {
return Err(HandshakeError::PeerIdentityMismatch);
}
}
if let Some(validators) = &self.client_validators {
for validator in validators.iter() {
validator.evaluate(&cert)?;
}
}
let cert_arc = Arc::new(cert);
self.client_cert = Some(Arc::clone(&cert_arc));
self.validated_client_cert = Some(cert_arc);
Ok(())
}
pub fn selected_profile(&self) -> Option<SecurityProfileDesc> {
self.selected_profile
}
fn compute_transcript_hash(&self) -> [u8; 32] {
compute_transcript_digest::<P::Digest>(&self.transcript_buffer)
}
fn validate_expected_state(&self, expected: ServerHandshakeState) -> Result<(), HandshakeError> {
validate_state(self.state.state(), expected)
}
fn process_security_offer(&mut self, unprotected_attrs: Option<&Attributes>) -> Result<(), HandshakeError> {
if unprotected_attrs.is_none() && self.supported_profiles.is_empty() {
return Ok(());
}
let offer = unprotected_attrs.and_then(|attrs| {
let handshake_attrs = self.convert_to_handshake_attributes(attrs).ok()?;
let offer_attr = attributes::find(&handshake_attrs, &oids::HANDSHAKE_SECURITY_OFFER).ok()?;
attributes::extract_security_offer(offer_attr).ok()
});
self.selected_profile = Some(self.negotiate_profile(offer.as_ref())?);
Ok(())
}
fn convert_to_handshake_attributes(
&self,
attrs: &Attributes,
) -> Result<Vec<attributes::HandshakeAttribute>, HandshakeError> {
attrs
.iter()
.map(|attr| {
Ok(attributes::HandshakeAttribute { attr_type: attr.oid, attr_values: attr.values.clone().into() })
})
.collect()
}
fn as_client_certificate(&self) -> Result<&Certificate, HandshakeError> {
self.client_cert
.as_ref()
.map(|arc| arc.as_ref())
.ok_or(HandshakeError::MissingClientCertificate)
}
fn extract_client_verifying_key(&self) -> Result<P::VerifyingKey, HandshakeError> {
let client_cert = self.as_client_certificate()?;
let client_public_key = extract_verifying_key_from_cert::<P::Curve>(client_cert)?;
Ok(P::VerifyingKey::from(client_public_key))
}
fn compute_client_signer_identifier(
&self,
client_verifying_key: &P::VerifyingKey,
) -> Result<SignerIdentifier, HandshakeError> {
Ok(crate::crypto::x509::utils::compute_signer_identifier::<P::Digest, _>(
client_verifying_key,
)?)
}
fn verify_client_signature(
&self,
signed_data_der: &[u8],
client_verifying_key: P::VerifyingKey,
expected_sid: SignerIdentifier,
) -> Result<Vec<u8>, HandshakeError> {
let verifier = EcdsaSignatureVerifier::<P::VerifyingKey, P::Signature, P::Digest>::from_verifying_key_with_sid(
client_verifying_key,
expected_sid,
);
let processor = TightBeamSignedDataProcessor::new(verifier);
let digest_oid = P::Digest::OID;
let verified_content = processor.process_der(signed_data_der, &digest_oid)?;
let expected_hash = self.transcript_hash.ok_or(HandshakeError::InvalidState)?;
if verified_content.len() != 32 || verified_content.as_slice() != expected_hash {
Err(HandshakeError::SignatureVerificationFailed)
} else {
Ok(verified_content)
}
}
async fn decrypt_session_key(&mut self, enveloped_data_der: &[u8]) -> Result<(), HandshakeError> {
let enveloped_data = EnvelopedData::from_der(enveloped_data_der)?;
let kari = enveloped_data
.recip_infos
.0
.iter()
.find_map(|ri| match ri {
RecipientInfo::Kari(kari) => Some(kari),
_ => None,
})
.ok_or_else(|| HandshakeError::InvalidClientKeyExchange)?;
let originator_pub_bytes = match &kari.originator {
OriginatorIdentifierOrKey::OriginatorKey(oipk) => oipk.public_key.raw_bytes(),
_ => return Err(HandshakeError::InvalidClientKeyExchange),
};
let shared_secret_bytes = self.server_key_provider.key_agreement(originator_pub_bytes).await?;
let ukm = kari.ukm.as_ref().ok_or(HandshakeError::MissingUkm)?;
let provider = P::default();
let kdf = provider.as_key_deriver::<HandshakeError, 32>();
let secret_bytes = Secret::from(shared_secret_bytes);
let mut kek = secret_bytes.with(|ss| kdf(ss, ukm.as_bytes(), TIGHTBEAM_KARI_KDF_INFO))??;
let wrapped_key = kari.recipient_enc_keys[0].enc_key.as_bytes();
let unwrapper = provider.as_key_unwrapper_32::<HandshakeError>();
let cek = unwrapper(wrapped_key, &kek)?;
let wrapper = provider.as_key_wrapper_32::<HandshakeError>();
let rewrapped = wrapper(&cek, &kek)?;
let valid = rewrapped.as_slice() == wrapped_key;
#[cfg(feature = "zeroize")]
{
use zeroize::Zeroize;
kek.zeroize();
}
if !valid {
return Err(HandshakeError::AesKeyWrap(
crate::crypto::aead::aes_kw::Error::IntegrityCheckFailed,
));
}
let cipher = P::AeadCipher::new_from_slice(&cek)
.map_err(|_| HandshakeError::InvalidKeySize { expected: 32, received: cek.len() })?;
let session_key_bytes = cipher.decrypt_content(&enveloped_data.encrypted_content)?;
self.session_key = Some(Secret::from(session_key_bytes));
Ok(())
}
pub async fn process_key_exchange(&mut self, enveloped_data_der: &[u8]) -> Result<(), HandshakeError> {
self.validate_expected_state(ServerHandshakeState::Init)?;
if self.transcript_hash.is_none() {
self.transcript_buffer.extend_from_slice(enveloped_data_der);
}
self.state.transition(ServerHandshakeState::KeyExchangeReceived)?;
let enveloped_data = EnvelopedData::from_der(enveloped_data_der)?;
self.check_for_alert(enveloped_data.unprotected_attrs.as_ref())?;
self.process_security_offer(enveloped_data.unprotected_attrs.as_ref())?;
self.decrypt_session_key(enveloped_data_der).await?;
if !self.invariants.transcript_locked {
self.invariants.lock_transcript()?;
}
self.invariants.derive_aead_once()?;
Ok(())
}
fn validate_server_finished_prerequisites(&self) -> Result<(), HandshakeError> {
self.validate_expected_state(ServerHandshakeState::KeyExchangeReceived)
}
fn prepare_server_finished_digest(&mut self) -> Result<Vec<u8>, HandshakeError> {
if self.transcript_hash.is_none() {
self.transcript_hash = Some(self.compute_transcript_hash());
}
let content = self.transcript_hash.as_ref().ok_or(HandshakeError::InvalidTranscriptHash)?;
let mut hasher = P::Digest::new();
hasher.update(content);
let digest = hasher.finalize();
Ok(digest.to_vec())
}
async fn sign_server_finished_digest(&self, digest: &[u8]) -> Result<Vec<u8>, HandshakeError> {
let signature_bytes = self.server_key_provider.sign(digest).await?;
Ok(signature_bytes)
}
async fn build_server_finished_crypto_components(
&self,
) -> Result<(SignerIdentifier, AlgorithmIdentifierOwned, AlgorithmIdentifierOwned), HandshakeError> {
use crate::crypto::x509::utils::compute_signer_identifier_from_der;
let public_key_bytes = self.server_key_provider.to_public_key_bytes().await?;
let signer_id = compute_signer_identifier_from_der::<P::Digest>(&public_key_bytes)?;
let digest_alg = AlgorithmIdentifierOwned { oid: P::Digest::OID, parameters: None };
let signature_alg = AlgorithmIdentifierOwned { oid: P::Signature::ALGORITHM_OID, parameters: None };
Ok((signer_id, digest_alg, signature_alg))
}
fn build_server_signed_data(
&self,
transcript_hash: [u8; 32],
signature_bytes: &[u8],
signer_id: SignerIdentifier,
digest_alg: AlgorithmIdentifierOwned,
signature_alg: AlgorithmIdentifierOwned,
) -> Result<Vec<u8>, HandshakeError> {
let signer_info = SignerInfo {
version: CmsVersion::V1,
sid: signer_id,
digest_alg: digest_alg.clone(),
signed_attrs: None,
signature_algorithm: signature_alg,
signature: OctetString::new(signature_bytes)?,
unsigned_attrs: None,
};
let octet_string = OctetString::new(transcript_hash)?;
let econtent_der = octet_string.to_der()?;
let econtent_any = crate::der::Any::from_der(&econtent_der)?;
let encap_content_info =
EncapsulatedContentInfo { econtent_type: crate::oids::DATA, econtent: Some(econtent_any) };
let signed_data = SignedData {
version: CmsVersion::V1,
digest_algorithms: vec![digest_alg].try_into()?,
encap_content_info,
certificates: None,
crls: None,
signer_infos: vec![signer_info].try_into()?,
};
signed_data.to_der().map_err(Into::into)
}
fn finalize_server_finished(&mut self, signed_data_der: &[u8]) -> Result<(), HandshakeError> {
if !self.transcript_buffer.is_empty() {
self.transcript_buffer.extend_from_slice(signed_data_der);
}
self.state.transition(ServerHandshakeState::ServerFinishedSent)?;
self.invariants.mark_finished_sent()?;
Ok(())
}
pub async fn build_server_finished(&mut self) -> Result<Vec<u8>, HandshakeError> {
self.validate_server_finished_prerequisites()?;
let digest = self.prepare_server_finished_digest()?;
let signature_bytes = self.sign_server_finished_digest(&digest).await?;
let (signer_id, digest_alg, signature_alg) = self.build_server_finished_crypto_components().await?;
let transcript_hash = self.transcript_hash.ok_or(HandshakeError::InvalidTranscriptHash)?;
let signed_data_der =
self.build_server_signed_data(transcript_hash, &signature_bytes, signer_id, digest_alg, signature_alg)?;
self.finalize_server_finished(&signed_data_der)?;
Ok(signed_data_der)
}
pub fn process_client_finished(&mut self, signed_data_der: &[u8]) -> Result<Vec<u8>, HandshakeError> {
self.validate_expected_state(ServerHandshakeState::ServerFinishedSent)?;
if !self.transcript_buffer.is_empty() {
self.transcript_buffer.extend_from_slice(signed_data_der);
}
let client_verifying_key = self.extract_client_verifying_key()?;
let expected_signer_identifier = self.compute_client_signer_identifier(&client_verifying_key)?;
let verified_content =
self.verify_client_signature(signed_data_der, client_verifying_key, expected_signer_identifier)?;
self.state.transition(ServerHandshakeState::ClientFinishedReceived)?;
Ok(verified_content)
}
pub fn complete(&mut self) -> Result<(), HandshakeError> {
self.validate_expected_state(ServerHandshakeState::ClientFinishedReceived)?;
self.state.transition(ServerHandshakeState::Completed)?;
Ok(())
}
pub fn state(&self) -> ServerHandshakeState {
self.state.state()
}
pub fn is_complete(&self) -> bool {
self.state.state().is_completed()
}
pub fn session_key(&self) -> Option<&Secret<Vec<u8>>> {
self.session_key.as_ref()
}
}
impl<P> HandshakeNegotiation for CmsHandshakeServer<P>
where
P: CryptoProvider,
{
fn supported_profiles(&self) -> &[SecurityProfileDesc] {
&self.supported_profiles
}
}
impl<P> HandshakeFinalization<P> for CmsHandshakeServer<P>
where
P: CryptoProvider,
{
fn selected_profile(&self) -> Option<SecurityProfileDesc> {
self.selected_profile
}
}
impl<P> HandshakeAlertHandler for CmsHandshakeServer<P> where P: CryptoProvider {}
impl<P> ServerHandshakeProtocol for CmsHandshakeServer<P>
where
P: CryptoProvider + Send + Sync + 'static,
P::Curve: Curve + CurveArithmetic,
<P::Curve as Curve>::FieldBytesSize: ModulusSize,
AffinePoint<P::Curve>: FromEncodedPoint<P::Curve> + ToEncodedPoint<P::Curve>,
P::VerifyingKey: From<PublicKey<P::Curve>> + EncodePublicKey + Verifier<P::Signature> + 'static,
P::Signature: 'static,
P::Digest: Send + 'static,
P::AeadCipher: Send + Sync + KeyInit + 'static,
{
type Error = HandshakeError;
fn handle_request<'a, 'b>(
&'a mut self,
msg: &'b [u8],
) -> core::pin::Pin<Box<dyn core::future::Future<Output = Result<Option<Vec<u8>>, Self::Error>> + Send + 'a>>
where
'b: 'a,
{
Box::pin(async move {
match self.state() {
ServerHandshakeState::Init => {
self.process_key_exchange(msg).await?;
let server_finished = self.build_server_finished().await?;
Ok(Some(server_finished))
}
ServerHandshakeState::ServerFinishedSent => {
self.process_client_finished(msg)?;
Ok(None)
}
_ => Err(HandshakeError::InvalidState),
}
})
}
#[cfg(feature = "aead")]
fn complete<'a>(
&'a mut self,
) -> core::pin::Pin<
Box<dyn core::future::Future<Output = Result<crate::crypto::aead::RuntimeAead, Self::Error>> + Send + 'a>,
> {
Box::pin(async move {
if self.state.state() != ServerHandshakeState::ClientFinishedReceived {
return Err(HandshakeError::InvalidState);
}
let cek = self.session_key.as_ref().ok_or(HandshakeError::InvalidState)?;
let profile = self.selected_profile.ok_or(HandshakeError::InvalidState)?;
let aead_oid = profile.aead.ok_or(HandshakeError::InvalidState)?;
use crate::transport::handshake::HandshakeFinalization;
let transcript = self.transcript_hash.as_ref().ok_or(HandshakeError::InvalidTranscriptHash)?;
let cipher = cek.with(|key_bytes| self.derive_session_aead(key_bytes, transcript))??;
self.state.transition(ServerHandshakeState::Completed)?;
Ok(crate::crypto::aead::RuntimeAead::new(cipher, aead_oid))
})
}
fn is_complete(&self) -> bool {
self.state.state().is_completed()
}
#[cfg(feature = "x509")]
fn peer_certificate(&self) -> Option<&Certificate> {
self.validated_client_cert.as_ref().map(|arc| arc.as_ref())
}
fn selected_profile(&self) -> Option<SecurityProfileDesc> {
self.selected_profile
}
}
#[cfg(test)]
mod tests {
mod server {
use super::super::*;
use crate::cms::cert::IssuerAndSerialNumber;
use crate::cms::enveloped_data::{KeyAgreeRecipientIdentifier, UserKeyingMaterial};
use crate::crypto::profiles::DefaultCryptoProvider;
use crate::crypto::sign::ecdsa::Secp256k1SigningKey;
use crate::crypto::sign::elliptic_curve::SecretKey;
use crate::crypto::x509::name::Name;
use crate::crypto::x509::serial_number::SerialNumber;
use crate::der::{Decode, Encode};
use crate::oids::{
AES_128_GCM, AES_128_WRAP, AES_256_GCM, AES_256_WRAP, CURVE_SECP256K1, HASH_SHA256, HASH_SHA3_256,
SIGNER_ECDSA_WITH_SHA256, SIGNER_ECDSA_WITH_SHA3_256,
};
use crate::random::{generate_nonce, OsRng};
use crate::spki::SubjectPublicKeyInfoOwned;
use crate::spki::{AlgorithmIdentifierOwned, EncodePublicKey};
use crate::transport::handshake::builders::{
TightBeamEnvelopedDataBuilder, TightBeamKariBuilder, TightBeamSignedDataBuilder,
};
use crate::transport::handshake::tests::*;
#[tokio::test]
async fn test_server_state_flow() -> Result<(), Box<dyn std::error::Error>> {
let transcript_hash = [1u8; 32];
let (mut server, server_public_key) =
TestCmsServerBuilder::new().with_transcript_hash(transcript_hash).build();
let client_test_cert = create_test_certificate();
server.set_client_certificate(client_test_cert.certificate.clone())?;
assert_eq!(server.state(), ServerHandshakeState::Init);
let key_exchange = build_test_key_exchange(&server_public_key, &[2u8; 32])?;
server.process_key_exchange(&key_exchange).await?;
assert_eq!(server.state(), ServerHandshakeState::KeyExchangeReceived);
assert!(server.session_key().is_some());
let _server_finished = server.build_server_finished().await?;
assert_eq!(server.state(), ServerHandshakeState::ServerFinishedSent);
let client_finished = build_test_client_finished(&client_test_cert.signing_key, &transcript_hash)?;
let verified = server.process_client_finished(&client_finished)?;
assert_eq!(verified, transcript_hash);
assert_eq!(server.state(), ServerHandshakeState::ClientFinishedReceived);
server.complete()?;
assert!(server.is_complete());
assert_eq!(server.state(), ServerHandshakeState::Completed);
Ok(())
}
#[tokio::test]
async fn test_invalid_state_transitions() -> Result<(), Box<dyn std::error::Error>> {
let (mut server, _) = TestCmsServerBuilder::new().build();
assert!(server.build_server_finished().await.is_err());
assert!(server.process_client_finished(&[]).is_err());
Ok(())
}
#[tokio::test]
async fn test_cms_end_to_end_with_profile_negotiation() -> Result<(), Box<dyn std::error::Error>> {
let transcript_hash = [1u8; 32];
let (mut server, server_public_key) =
TestCmsServerBuilder::new().with_transcript_hash(transcript_hash).build();
let profiles = vec![
create_aes_gcm_profile(16), create_aes_gcm_profile(32), ];
server = server.with_supported_profiles(profiles);
let client_test_cert = create_test_certificate();
server.set_client_certificate(client_test_cert.certificate.clone())?;
let key_exchange = build_test_key_exchange(&server_public_key, &[2u8; 32])?;
server.process_key_exchange(&key_exchange).await?;
assert_eq!(server.state(), ServerHandshakeState::KeyExchangeReceived);
assert!(server.session_key().is_some());
assert!(server.selected_profile.is_some());
let selected = server.selected_profile.unwrap();
assert!(selected.aead.is_some());
let _server_finished = server.build_server_finished().await?;
assert_eq!(server.state(), ServerHandshakeState::ServerFinishedSent);
let client_finished = build_test_client_finished(&client_test_cert.signing_key, &transcript_hash)?;
server.process_client_finished(&client_finished)?;
assert_eq!(server.state(), ServerHandshakeState::ClientFinishedReceived);
server.complete()?;
assert_eq!(server.state(), ServerHandshakeState::Completed);
assert!(server.is_complete());
assert!(server.session_key().is_some());
Ok(())
}
fn build_test_key_exchange(
recipient_public_key: &PublicKey<k256::Secp256k1>,
session_key: &[u8],
) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
let sender_ephemeral = SecretKey::<k256::Secp256k1>::random(&mut OsRng);
let sender_public = sender_ephemeral.public_key();
let sender_pub_spki = sender_public.to_public_key_der()?;
let sender_pub_spki = SubjectPublicKeyInfoOwned::from_der(sender_pub_spki.as_bytes())?;
let ukm_bytes = generate_nonce::<64>(None)?;
let ukm = UserKeyingMaterial::new(ukm_bytes.to_vec())?;
let rid = KeyAgreeRecipientIdentifier::IssuerAndSerialNumber(IssuerAndSerialNumber {
issuer: Name::default(),
serial_number: SerialNumber::new(&[0x01])?,
});
let key_enc_alg = AlgorithmIdentifierOwned { oid: AES_128_WRAP, parameters: None };
let kari_builder = TightBeamKariBuilder::default()
.with_sender_priv(sender_ephemeral)
.with_sender_pub_spki(sender_pub_spki)
.with_recipient_pub(*recipient_public_key)
.with_recipient_rid(rid)
.with_ukm(ukm)
.with_key_enc_alg(key_enc_alg);
let enveloped_builder = TightBeamEnvelopedDataBuilder::with_defaults(kari_builder);
let enveloped_data = enveloped_builder.build(session_key, None)?;
Ok(enveloped_data.to_der()?)
}
fn build_test_client_finished(
signing_key: &Secp256k1SigningKey,
transcript_hash: &[u8],
) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
let digest_alg = AlgorithmIdentifierOwned { oid: HASH_SHA3_256, parameters: None };
let signature_alg = AlgorithmIdentifierOwned { oid: SIGNER_ECDSA_WITH_SHA3_256, parameters: None };
let builder =
TightBeamSignedDataBuilder::<DefaultCryptoProvider, _>::new(signing_key, digest_alg, signature_alg)?;
let signed_data = builder.build(transcript_hash)?;
Ok(signed_data.to_der()?)
}
fn create_aes_gcm_profile(key_size: u16) -> SecurityProfileDesc {
let aead_oid = if key_size == 16 {
AES_128_GCM
} else {
AES_256_GCM
};
let key_wrap_oid = if key_size == 16 {
AES_128_WRAP
} else {
AES_256_WRAP
};
SecurityProfileDesc {
digest: HASH_SHA256,
aead: Some(aead_oid),
aead_key_size: Some(key_size),
signature: Some(SIGNER_ECDSA_WITH_SHA256),
kdf: Some(HASH_SHA256), curve: Some(CURVE_SECP256K1),
key_wrap: Some(key_wrap_oid),
kem: None,
}
}
}
}