#![allow(clippy::unwrap_used, missing_docs, clippy::missing_docs_in_private_items)]
use std::{str::FromStr, time::Duration};
use der::{
Encode,
asn1::{BitString, UtcTime},
};
use ed25519_dalek::{Signature as Ed25519DalekSignature, Signer, SigningKey, VerifyingKey};
use polyproto::{
certs::{
PublicKeyInfo,
capabilities::ActorCapabilities,
idcert::{IdCertActor, traits::IdCertBehaviors as _},
idcerttbs::IdCertTbsActor,
idcsr::{IdCsrActor, IdCsrBehaviors as _},
},
errors::composite::{CertificateConversionError, PublicKeyError},
key::{PrivateKey, PublicKey},
signature::Signature,
types::{
DomainName, FederationId, LocalName, SessionId,
pdn::{ActorDN, HomeServerDN},
x509_cert::SerialNumber,
},
};
use rand::rngs::OsRng;
use spki::{AlgorithmIdentifierOwned, ObjectIdentifier, SignatureBitStringEncoding};
use x509_cert::{
Certificate,
name::RelativeDistinguishedName,
time::{Time, Validity},
};
#[allow(clippy::unwrap_used)]
fn main() {
let mut csprng = rand::rngs::OsRng;
let priv_key = Ed25519PrivateKey::gen_keypair(&mut csprng);
println!("Private Key is: {:?}", priv_key.key.to_bytes());
println!("Public Key is: {:?}", priv_key.public_key.key.to_bytes());
println!();
let actor_dn = ActorDN {
federation_id: FederationId::new("flori@polyphony.chat").unwrap(),
local_name: LocalName::new("flori").unwrap(),
domain_name: DomainName::new("polyphony.chat").unwrap(),
session_id: SessionId::new_validated("client1").unwrap(),
additional_fields: RelativeDistinguishedName::default(),
};
let home_server_dn = HomeServerDN {
domain_name: DomainName::new("polyphony.chat").unwrap(),
additional_fields: RelativeDistinguishedName::default(),
};
let validity = Validity {
not_before: Time::UtcTime(UtcTime::from_unix_duration(Duration::from_secs(10)).unwrap()),
not_after: Time::UtcTime(UtcTime::from_unix_duration(Duration::from_secs(1000)).unwrap()),
};
let csr = IdCsrActor::new(actor_dn.clone(), &priv_key, ActorCapabilities::default()).unwrap();
let csr_der = csr.clone().to_der().unwrap();
std::fs::write("cert.csr", &csr_der).unwrap();
println!("Wrote actor CSR to cert.csr ({} bytes)", csr_der.len());
let tbs = IdCertTbsActor {
serial_number: SerialNumber::from_bytes_be(&8932489u64.to_be_bytes()).unwrap(),
signature_algorithm: Ed25519Signature::algorithm_identifier(),
issuer: home_server_dn.clone(),
validity,
subject: actor_dn,
subject_public_key: priv_key.pubkey().clone(),
capabilities: ActorCapabilities::default(),
s: Default::default(),
};
let cert = IdCertActor::try_from_tbs(
&tbs,
&priv_key,
SerialNumber::from_bytes_be(&8932489u64.to_be_bytes()).unwrap(),
home_server_dn,
validity,
)
.unwrap();
let cert_der = Certificate::try_from(cert).unwrap().to_der().unwrap();
#[cfg(not(target_arch = "wasm32"))]
std::fs::write("cert.der", &cert_der).unwrap();
println!("Wrote actor ID-Cert to cert.der ({} bytes)", cert_der.len());
}
#[derive(Debug, PartialEq, Eq, Clone)]
#[allow(missing_docs)]
struct Ed25519Signature {
#[allow(missing_docs)]
signature: Ed25519DalekSignature,
#[allow(missing_docs)]
algorithm: AlgorithmIdentifierOwned,
}
impl std::fmt::Display for Ed25519Signature {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self.signature)
}
}
impl Signature for Ed25519Signature {
type Signature = Ed25519DalekSignature;
fn as_bytes(&self) -> Vec<u8> {
self.as_signature().to_vec()
}
fn as_signature(&self) -> &Self::Signature {
&self.signature
}
fn algorithm_identifier() -> AlgorithmIdentifierOwned {
AlgorithmIdentifierOwned {
oid: ObjectIdentifier::from_str("1.3.101.112").unwrap(),
parameters: None,
}
}
#[cfg(not(tarpaulin_include))]
fn from_bytes(signature: &[u8]) -> Result<Ed25519Signature, polyproto::errors::InvalidInput> {
if signature.len() != 64 {
return Err(polyproto::errors::InvalidInput::Length {
min_length: 64,
max_length: 64,
actual_length: signature.len().to_string(),
});
}
let signature_array: [u8; 64] = {
let mut array = [0; 64];
array.copy_from_slice(signature);
array
};
Ok(Self {
signature: Ed25519DalekSignature::from_bytes(&signature_array),
algorithm: Self::algorithm_identifier(),
})
}
}
impl SignatureBitStringEncoding for Ed25519Signature {
fn to_bitstring(&self) -> der::Result<der::asn1::BitString> {
BitString::from_bytes(&self.as_signature().to_bytes())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[allow(missing_docs)]
struct Ed25519PrivateKey {
#[allow(missing_docs)]
public_key: Ed25519PublicKey,
#[allow(missing_docs)]
key: SigningKey,
}
impl PrivateKey<Ed25519Signature> for Ed25519PrivateKey {
type PublicKey = Ed25519PublicKey;
fn pubkey(&self) -> &Self::PublicKey {
&self.public_key
}
fn sign(&self, data: &[u8]) -> Ed25519Signature {
let signature = self.key.sign(data);
Ed25519Signature { signature, algorithm: self.algorithm_identifier() }
}
}
impl Ed25519PrivateKey {
#[allow(missing_docs)]
pub fn gen_keypair(csprng: &mut OsRng) -> Self {
let key = SigningKey::generate(csprng);
let public_key = Ed25519PublicKey { key: key.verifying_key() };
Self { public_key, key }
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[allow(missing_docs)]
struct Ed25519PublicKey {
#[allow(missing_docs)]
key: VerifyingKey,
}
impl PublicKey<Ed25519Signature> for Ed25519PublicKey {
#[cfg(not(tarpaulin_include))]
fn verify_signature(
&self,
signature: &Ed25519Signature,
data: &[u8],
) -> Result<(), PublicKeyError> {
match self.key.verify_strict(data, signature.as_signature()) {
Ok(_) => Ok(()),
Err(_) => Err(PublicKeyError::BadSignature),
}
}
fn public_key_info(&self) -> Result<PublicKeyInfo, PublicKeyError> {
let bitstring = BitString::from_bytes(&self.key.to_bytes())
.map_err(|_| PublicKeyError::BadPublicKeyInfo)?;
Ok(PublicKeyInfo {
algorithm: Ed25519Signature::algorithm_identifier(),
public_key_bitstring: bitstring,
})
}
#[cfg(not(tarpaulin_include))]
fn try_from_public_key_info(
public_key_info: PublicKeyInfo,
) -> std::result::Result<Ed25519PublicKey, CertificateConversionError> {
let mut key_vec = public_key_info.public_key_bitstring.raw_bytes().to_vec();
key_vec.resize(32, 0);
let signature_array: [u8; 32] = {
let mut array = [0; 32];
array.copy_from_slice(&key_vec[..]);
array
};
Ok(Self { key: VerifyingKey::from_bytes(&signature_array).unwrap() })
}
}
#[test]
fn test_example() {
main()
}