use openmls_traits::{
types::{CryptoError, SignatureScheme},
OpenMlsCryptoProvider,
};
use serde::{Deserialize, Serialize};
use std::convert::TryFrom;
#[cfg(test)]
use tls_codec::Serialize as TlsSerializeTrait;
use tls_codec::{TlsByteVecU16, TlsDeserialize, TlsSerialize, TlsSize};
use crate::{ciphersuite::*, error::LibraryError};
mod codec;
#[cfg(test)]
mod tests;
use errors::*;
pub mod errors;
#[derive(
Copy, Clone, Debug, PartialEq, Serialize, Deserialize, TlsDeserialize, TlsSerialize, TlsSize,
)]
#[repr(u16)]
pub enum CredentialType {
Basic = 1,
X509 = 2,
}
impl TryFrom<u16> for CredentialType {
type Error = &'static str;
fn try_from(value: u16) -> Result<Self, Self::Error> {
match value {
1 => Ok(CredentialType::Basic),
2 => Ok(CredentialType::X509),
_ => Err("Undefined CredentialType"),
}
}
}
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
pub struct Certificate {
cert_data: Vec<u8>,
}
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
pub enum MlsCredentialType {
Basic(BasicCredential),
X509(Certificate),
}
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
pub struct Credential {
credential_type: CredentialType,
credential: MlsCredentialType,
}
impl Credential {
pub fn verify(
&self,
backend: &impl OpenMlsCryptoProvider,
payload: &[u8],
signature: &Signature,
) -> Result<(), CredentialError> {
match &self.credential {
MlsCredentialType::Basic(basic_credential) => basic_credential
.public_key
.verify(backend, signature, payload)
.map_err(|_| CredentialError::InvalidSignature),
MlsCredentialType::X509(_) => panic!("X509 certificates are not yet implemented."),
}
}
pub fn identity(&self) -> &[u8] {
match &self.credential {
MlsCredentialType::Basic(basic_credential) => basic_credential.identity.as_slice(),
MlsCredentialType::X509(_) => panic!("X509 certificates are not yet implemented."),
}
}
pub fn signature_scheme(&self) -> SignatureScheme {
match &self.credential {
MlsCredentialType::Basic(basic_credential) => basic_credential.signature_scheme,
MlsCredentialType::X509(_) => panic!("X509 certificates are not yet implemented."),
}
}
pub fn signature_key(&self) -> &SignaturePublicKey {
match &self.credential {
MlsCredentialType::Basic(basic_credential) => &basic_credential.public_key,
MlsCredentialType::X509(_) => panic!("X509 certificates are not yet implemented."),
}
}
}
impl From<MlsCredentialType> for Credential {
fn from(mls_credential_type: MlsCredentialType) -> Self {
Credential {
credential_type: match mls_credential_type {
MlsCredentialType::Basic(_) => CredentialType::Basic,
MlsCredentialType::X509(_) => CredentialType::X509,
},
credential: mls_credential_type,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, TlsSerialize, TlsSize)]
pub struct BasicCredential {
identity: TlsByteVecU16,
signature_scheme: SignatureScheme,
public_key: SignaturePublicKey,
}
impl BasicCredential {
pub fn verify(
&self,
backend: &impl OpenMlsCryptoProvider,
payload: &[u8],
signature: &Signature,
) -> Result<(), CredentialError> {
self.public_key
.verify(backend, signature, payload)
.map_err(|_| CredentialError::InvalidSignature)
}
}
impl PartialEq for BasicCredential {
fn eq(&self, other: &Self) -> bool {
self.identity == other.identity && self.public_key == other.public_key
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(any(feature = "test-utils", test), derive(PartialEq))]
pub struct CredentialBundle {
credential: Credential,
signature_private_key: SignaturePrivateKey,
}
impl CredentialBundle {
pub fn new(
identity: Vec<u8>,
credential_type: CredentialType,
signature_scheme: SignatureScheme,
backend: &impl OpenMlsCryptoProvider,
) -> Result<Self, CredentialError> {
let (private_key, public_key) = SignatureKeypair::new(signature_scheme, backend)
.map_err(LibraryError::unexpected_crypto_error)?
.into_tuple();
let mls_credential = match credential_type {
CredentialType::Basic => BasicCredential {
identity: identity.into(),
signature_scheme,
public_key,
},
_ => return Err(CredentialError::UnsupportedCredentialType),
};
let credential = Credential {
credential_type,
credential: MlsCredentialType::Basic(mls_credential),
};
Ok(CredentialBundle {
credential,
signature_private_key: private_key,
})
}
pub fn from_parts(identity: Vec<u8>, keypair: SignatureKeypair) -> Self {
let (signature_private_key, public_key) = keypair.into_tuple();
let basic_credential = BasicCredential {
identity: identity.into(),
signature_scheme: public_key.signature_scheme(),
public_key,
};
let credential = Credential {
credential_type: CredentialType::Basic,
credential: MlsCredentialType::Basic(basic_credential),
};
Self {
credential,
signature_private_key,
}
}
pub fn credential(&self) -> &Credential {
&self.credential
}
pub fn into_parts(self) -> (Credential, SignaturePrivateKey) {
(self.credential, self.signature_private_key)
}
pub(crate) fn sign(
&self,
backend: &impl OpenMlsCryptoProvider,
msg: &[u8],
) -> Result<Signature, CryptoError> {
self.signature_private_key.sign(backend, msg)
}
#[cfg(any(feature = "test-utils", test))]
pub fn key_pair(&self) -> SignatureKeypair {
let public_key = self.credential().signature_key().clone();
let private_key = self.signature_private_key.clone();
SignatureKeypair::from_parts(public_key, private_key)
}
}