#![allow(clippy::unwrap_used, clippy::arithmetic_side_effects, dead_code, missing_docs)]
#[cfg(feature = "reqwest")]
mod reqwest_example {
use std::str::FromStr;
use der::asn1::BitString;
use ed25519_dalek::{
Signature as Ed25519DalekSignature, SigningKey, VerifyingKey, ed25519::signature::Signer,
};
use httptest::{Expectation, Server, matchers::request, responders::json_encoded};
use polyproto::{
api::{HttpClient, core::current_unix_time},
certs::PublicKeyInfo,
errors::{CertificateConversionError, composite::PublicKeyError},
key::{PrivateKey, PublicKey},
signature::Signature,
types::routes::core::v1::GET_CHALLENGE_STRING,
};
use rand::rngs::OsRng;
use serde_json::json;
use spki::{AlgorithmIdentifierOwned, ObjectIdentifier, SignatureBitStringEncoding};
use url::Url;
pub fn setup_example() -> Server {
let server = Server::run();
server.expect(
Expectation::matching(request::method_path(
GET_CHALLENGE_STRING.method.as_str(),
GET_CHALLENGE_STRING.path,
))
.respond_with(json_encoded(json!({
"challenge": "abcd".repeat(8),
"expires": current_unix_time() + 100
}))),
);
server
}
pub async fn run_example() {
let server = setup_example();
let url = format!("http://{}", server.addr());
let client = HttpClient::new().unwrap();
let _session: polyproto::api::Session<Ed25519Signature, Ed25519PrivateKey> =
polyproto::api::Session::new(&client, "12345", Url::parse(&url).unwrap(), None);
let cert = client
.get_server_id_cert(None, &Url::parse("https://example.com/").unwrap())
.await
.unwrap();
dbg!(cert);
}
#[cfg(test)]
pub fn test_main() {
tokio::runtime::Runtime::new().unwrap().block_on(run_example())
}
#[tokio::main]
pub async fn main() {
run_example().await
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub(crate) struct Ed25519Signature {
pub(crate) signature: Ed25519DalekSignature,
pub(crate) 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_signature(&self) -> &Self::Signature {
&self.signature
}
fn algorithm_identifier() -> AlgorithmIdentifierOwned {
AlgorithmIdentifierOwned {
oid: ObjectIdentifier::from_str("1.3.101.112").unwrap(),
parameters: None,
}
}
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(),
})
}
fn as_bytes(&self) -> Vec<u8> {
self.as_signature().to_vec()
}
}
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)]
pub(crate) struct Ed25519PrivateKey {
pub(crate) public_key: Ed25519PublicKey,
pub(crate) 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 {
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)]
pub(crate) struct Ed25519PublicKey {
pub(crate) key: VerifyingKey,
}
impl PublicKey<Ed25519Signature> for Ed25519PublicKey {
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, polyproto::errors::PublicKeyError> {
let bitstring = BitString::from_bytes(&self.key.to_bytes())
.map_err(|_| polyproto::errors::PublicKeyError::BadPublicKeyInfo)?;
Ok(PublicKeyInfo {
algorithm: Ed25519Signature::algorithm_identifier(),
public_key_bitstring: bitstring,
})
}
fn try_from_public_key_info(
public_key_info: PublicKeyInfo,
) -> Result<Self, 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() })
}
}
}
#[cfg(feature = "reqwest")]
#[tokio::main]
async fn main() {
reqwest_example::run_example().await
}
#[cfg(not(feature = "reqwest"))]
fn main() {
eprintln!("This example requires you to compile with the 'reqwest' feature enabled.")
}