feat(tls/tests): move and adapt TLS tests into alknet-tls
Phase 1, Task 4 of crate extraction. Moves 34 tests into alknet-tls: - server.rs: 16 tests (RawKeyCertResolver, SelfSignedCert, AcmeDirectory, TlsServerConfig, build_rustls_server_config, build_quinn_server_config, AcceptAnyCertVerifier) - client.rs: 10 tests (FingerprintPinVerifier, select_server_verifier, build_client_auth, TlsClientConfig::new + for_quinn) - signing.rs: 6 tests (Ed25519SigningKey trait impls) - pem.rs: 3 tests (load_cert_chain, load_private_key error paths) build_quinn_client_config tests adapted to use TlsClientConfig::new().for_quinn(). tls_setup_x509 test adapted to use TlsServerConfig::new(). Test helpers (build_ed25519_spki_der, build_x509_cert_der, aws_lc_rs_provider, verify_pin) moved with their tests. Old tests stay in endpoint.rs and call_client.rs (duplicated). No breakage.
This commit is contained in:
1 parent
effbd4174e
commit
b749fa8019
4 files changed
+470
No files matched your search
@@ -316,3 +316,201 @@ impl rustls::client::danger::ServerCertVerifier for FingerprintPinVerifier {
|
|||||||
self.supported.supported_schemes()
|
self.supported.supported_schemes()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use alknet_core::config::Ed25519SecretKey;
|
||||||
|
|
||||||
|
fn build_ed25519_spki_der(raw_key: &[u8; 32]) -> Vec<u8> {
|
||||||
|
let spki = rustls::sign::public_key_to_spki(&rustls::pki_types::alg_id::ED25519, raw_key);
|
||||||
|
spki.to_vec()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_x509_cert_der() -> rustls::pki_types::CertificateDer<'static> {
|
||||||
|
let key_pair = rcgen::KeyPair::generate().expect("key gen");
|
||||||
|
let params = rcgen::CertificateParams::default();
|
||||||
|
let cert = params.self_signed(&key_pair).expect("self-signed cert");
|
||||||
|
cert.der().clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn aws_lc_rs_provider() -> Arc<rustls::crypto::CryptoProvider> {
|
||||||
|
Arc::new(rustls::crypto::aws_lc_rs::default_provider())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn verify_pin(
|
||||||
|
verifier: &FingerprintPinVerifier,
|
||||||
|
cert_der: rustls::pki_types::CertificateDer<'_>,
|
||||||
|
) -> Result<rustls::client::danger::ServerCertVerified, rustls::Error> {
|
||||||
|
use rustls::client::danger::ServerCertVerifier;
|
||||||
|
let server_name: rustls::pki_types::ServerName<'static> =
|
||||||
|
"alknet".try_into().expect("server name");
|
||||||
|
verifier.verify_server_cert(
|
||||||
|
&cert_der,
|
||||||
|
&[],
|
||||||
|
&server_name,
|
||||||
|
&[],
|
||||||
|
rustls::pki_types::UnixTime::now(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn fingerprint_pin_verifier_matches_correct_ed25519_fingerprint() {
|
||||||
|
let sk = Ed25519SecretKey::generate();
|
||||||
|
let raw_key = sk.public().to_bytes();
|
||||||
|
let spki_der = build_ed25519_spki_der(&raw_key);
|
||||||
|
let fingerprint =
|
||||||
|
alknet_core::fingerprint::fingerprint_from_cert_der(&spki_der).expect("fingerprint");
|
||||||
|
let verifier = FingerprintPinVerifier::new(
|
||||||
|
fingerprint,
|
||||||
|
aws_lc_rs_provider().signature_verification_algorithms,
|
||||||
|
);
|
||||||
|
let cert = rustls::pki_types::CertificateDer::from(spki_der);
|
||||||
|
let result = verify_pin(&verifier, cert);
|
||||||
|
assert!(
|
||||||
|
result.is_ok(),
|
||||||
|
"FingerprintPinVerifier must accept a cert whose fingerprint matches the pin"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn fingerprint_pin_verifier_rejects_wrong_ed25519_fingerprint() {
|
||||||
|
let sk = Ed25519SecretKey::generate();
|
||||||
|
let raw_key = sk.public().to_bytes();
|
||||||
|
let spki_der = build_ed25519_spki_der(&raw_key);
|
||||||
|
let other_sk = Ed25519SecretKey::generate();
|
||||||
|
let other_fp = format!("ed25519:{}", hex::encode(other_sk.public().to_bytes()));
|
||||||
|
let verifier = FingerprintPinVerifier::new(
|
||||||
|
other_fp,
|
||||||
|
aws_lc_rs_provider().signature_verification_algorithms,
|
||||||
|
);
|
||||||
|
let cert = rustls::pki_types::CertificateDer::from(spki_der);
|
||||||
|
let result = verify_pin(&verifier, cert);
|
||||||
|
assert!(
|
||||||
|
result.is_err(),
|
||||||
|
"FingerprintPinVerifier must reject a cert whose fingerprint does not match the pin"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn fingerprint_pin_verifier_matches_correct_sha256_fingerprint() {
|
||||||
|
let cert_der = build_x509_cert_der();
|
||||||
|
let fingerprint = alknet_core::fingerprint::fingerprint_from_cert_der(cert_der.as_ref())
|
||||||
|
.expect("fingerprint");
|
||||||
|
let verifier = FingerprintPinVerifier::new(
|
||||||
|
fingerprint,
|
||||||
|
aws_lc_rs_provider().signature_verification_algorithms,
|
||||||
|
);
|
||||||
|
let result = verify_pin(&verifier, cert_der);
|
||||||
|
assert!(
|
||||||
|
result.is_ok(),
|
||||||
|
"FingerprintPinVerifier must accept an X.509 cert whose SHA256 fingerprint matches"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn fingerprint_pin_verifier_rejects_wrong_sha256_fingerprint() {
|
||||||
|
let cert_der = build_x509_cert_der();
|
||||||
|
let verifier = FingerprintPinVerifier::new(
|
||||||
|
"SHA256:0000000000000000000000000000000000000000000000000000000000000000".to_string(),
|
||||||
|
aws_lc_rs_provider().signature_verification_algorithms,
|
||||||
|
);
|
||||||
|
let result = verify_pin(&verifier, cert_der);
|
||||||
|
assert!(
|
||||||
|
result.is_err(),
|
||||||
|
"FingerprintPinVerifier must reject an X.509 cert whose SHA256 does not match"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn select_server_verifier_returns_ca_verifier_for_none() {
|
||||||
|
let provider = aws_lc_rs_provider();
|
||||||
|
let remote_identity: Option<RemoteIdentity> = None;
|
||||||
|
let verifier = select_server_verifier(&provider, &remote_identity);
|
||||||
|
assert!(
|
||||||
|
verifier.is_ok(),
|
||||||
|
"select_server_verifier must succeed for None (CA path)"
|
||||||
|
);
|
||||||
|
let debug = format!("{:?}", verifier.unwrap());
|
||||||
|
assert!(
|
||||||
|
debug.contains("WebPkiServerVerifier"),
|
||||||
|
"None must select WebPkiServerVerifier (CA verification), got: {debug}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn select_server_verifier_returns_fingerprint_pin_for_some() {
|
||||||
|
let provider = aws_lc_rs_provider();
|
||||||
|
let remote_identity = Some(RemoteIdentity {
|
||||||
|
fingerprint: "ed25519:abc".to_string(),
|
||||||
|
});
|
||||||
|
let verifier = select_server_verifier(&provider, &remote_identity);
|
||||||
|
assert!(
|
||||||
|
verifier.is_ok(),
|
||||||
|
"select_server_verifier must succeed for Some (fingerprint pin path)"
|
||||||
|
);
|
||||||
|
let debug = format!("{:?}", verifier.unwrap());
|
||||||
|
assert!(
|
||||||
|
debug.contains("FingerprintPinVerifier"),
|
||||||
|
"Some must select FingerprintPinVerifier, got: {debug}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn build_client_auth_presents_ed25519_raw_key_without_error() {
|
||||||
|
let provider = aws_lc_rs_provider();
|
||||||
|
let sk = Ed25519SecretKey::generate();
|
||||||
|
let tls_identity = Some(TlsIdentity::RawKey(sk));
|
||||||
|
let resolver = build_client_auth(&provider, &tls_identity);
|
||||||
|
assert!(
|
||||||
|
resolver.is_ok(),
|
||||||
|
"build_client_auth must build a resolver for a RawKey identity"
|
||||||
|
);
|
||||||
|
let resolver = resolver.unwrap();
|
||||||
|
assert!(
|
||||||
|
resolver.only_raw_public_keys(),
|
||||||
|
"RawKey client auth resolver must present raw public keys (RFC 7250)"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
resolver.has_certs(),
|
||||||
|
"RawKey client auth resolver must report it has a cert to present"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn build_client_auth_none_resolves_to_no_client_cert() {
|
||||||
|
let provider = aws_lc_rs_provider();
|
||||||
|
let tls_identity: Option<TlsIdentity> = None;
|
||||||
|
let resolver = build_client_auth(&provider, &tls_identity)
|
||||||
|
.expect("build_client_auth must succeed for None");
|
||||||
|
assert!(
|
||||||
|
!resolver.has_certs(),
|
||||||
|
"NoClientCertResolver must report no certs (no client cert presented)"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn build_quinn_client_config_with_raw_key_identity_builds_without_error() {
|
||||||
|
let sk = Ed25519SecretKey::generate();
|
||||||
|
let credentials = ConnectionCredentials::new()
|
||||||
|
.with_tls_identity(TlsIdentity::RawKey(sk))
|
||||||
|
.with_remote_identity(RemoteIdentity {
|
||||||
|
fingerprint: "ed25519:deadbeef".to_string(),
|
||||||
|
});
|
||||||
|
let config = TlsClientConfig::new(&credentials, b"alknet/call")
|
||||||
|
.expect("TlsClientConfig::new must build");
|
||||||
|
let quinn_config = config.for_quinn().expect("for_quinn must convert");
|
||||||
|
let _ = quinn_config;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn build_quinn_client_config_with_no_remote_identity_builds_without_error() {
|
||||||
|
let sk = Ed25519SecretKey::generate();
|
||||||
|
let credentials =
|
||||||
|
ConnectionCredentials::new().with_tls_identity(TlsIdentity::RawKey(sk));
|
||||||
|
let config = TlsClientConfig::new(&credentials, b"alknet/call")
|
||||||
|
.expect("TlsClientConfig::new must build for CA-verification path");
|
||||||
|
let quinn_config = config.for_quinn().expect("for_quinn must convert");
|
||||||
|
let _ = quinn_config;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -30,3 +30,42 @@ pub fn load_private_key(
|
|||||||
Err(e) => Err(TlsError::Io(io::Error::other(e))),
|
Err(e) => Err(TlsError::Io(io::Error::other(e))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn load_private_key_returns_error_when_no_key_present() {
|
||||||
|
let dir = tempfile::tempdir().unwrap();
|
||||||
|
let empty = dir.path().join("empty.key");
|
||||||
|
std::fs::write(&empty, b"# no key here\njust a comment\n").unwrap();
|
||||||
|
let err = load_private_key(&empty);
|
||||||
|
assert!(
|
||||||
|
matches!(err, Err(TlsError::Io(_))),
|
||||||
|
"empty key file must yield Io error, got {err:?}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn load_private_key_returns_error_when_file_missing() {
|
||||||
|
let err = load_private_key(std::path::Path::new(
|
||||||
|
"/nonexistent/alknet-coverage/missing.key",
|
||||||
|
));
|
||||||
|
assert!(
|
||||||
|
matches!(err, Err(TlsError::Io(_))),
|
||||||
|
"missing key file must yield Io error, got {err:?}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn load_cert_chain_returns_error_when_file_missing() {
|
||||||
|
let err = load_cert_chain(std::path::Path::new(
|
||||||
|
"/nonexistent/alknet-coverage/missing.pem",
|
||||||
|
));
|
||||||
|
assert!(
|
||||||
|
matches!(err, Err(TlsError::Io(_))),
|
||||||
|
"missing cert file must yield Io error, got {err:?}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -334,3 +334,167 @@ impl std::fmt::Debug for RawKeyCertResolver {
|
|||||||
f.debug_struct("RawKeyCertResolver").finish()
|
f.debug_struct("RawKeyCertResolver").finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use alknet_core::config::AcmeDirectory;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn raw_key_cert_resolver_only_raw_public_keys() {
|
||||||
|
use rustls::server::ResolvesServerCert;
|
||||||
|
let sk = Ed25519SecretKey::generate();
|
||||||
|
let resolver = RawKeyCertResolver::new(&sk);
|
||||||
|
assert!(resolver.only_raw_public_keys());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn self_signed_cert_generation_produces_cert_and_key() {
|
||||||
|
let cert = generate_self_signed_cert().expect("self-signed cert generates");
|
||||||
|
assert!(!cert.cert_chain.is_empty());
|
||||||
|
assert!(!cert.private_key.secret_der().is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn acme_directory_production_url() {
|
||||||
|
let dir = AcmeDirectory::Production;
|
||||||
|
assert_eq!(dir.url(), "https://acme-v02.api.letsencrypt.org/directory");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn acme_directory_staging_url() {
|
||||||
|
let dir = AcmeDirectory::Staging;
|
||||||
|
assert_eq!(
|
||||||
|
dir.url(),
|
||||||
|
"https://acme-staging-v02.api.letsencrypt.org/directory"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn acme_directory_custom_url() {
|
||||||
|
let url = "https://custom-acme.example.com/directory";
|
||||||
|
let dir = AcmeDirectory::Custom(url.to_string());
|
||||||
|
assert_eq!(dir.url(), url);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn tls_setup_x509_returns_no_acme_state() {
|
||||||
|
use rcgen::{CertificateParams, KeyPair};
|
||||||
|
let key_pair = KeyPair::generate().unwrap();
|
||||||
|
let params = CertificateParams::default();
|
||||||
|
let cert = params.self_signed(&key_pair).unwrap();
|
||||||
|
let cert_pem = cert.pem();
|
||||||
|
let key_pem = key_pair.serialize_pem();
|
||||||
|
|
||||||
|
let dir = tempfile::tempdir().unwrap();
|
||||||
|
let cert_path = dir.path().join("cert.pem");
|
||||||
|
let key_path = dir.path().join("key.pem");
|
||||||
|
std::fs::write(&cert_path, cert_pem).unwrap();
|
||||||
|
std::fs::write(&key_path, key_pem).unwrap();
|
||||||
|
|
||||||
|
let tls_identity = TlsIdentity::X509 {
|
||||||
|
cert: cert_path,
|
||||||
|
key: key_path,
|
||||||
|
};
|
||||||
|
let setup = TlsServerConfig::new(&tls_identity, &[b"alknet/test".to_vec()])
|
||||||
|
.await
|
||||||
|
.expect("X509 tls setup should succeed");
|
||||||
|
let _ = setup.rustls_config;
|
||||||
|
#[cfg(feature = "acme")]
|
||||||
|
assert!(setup.acme_state_handle.is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn build_rustls_server_config_raw_key_succeeds() {
|
||||||
|
let sk = Ed25519SecretKey::generate();
|
||||||
|
let identity = TlsIdentity::RawKey(sk);
|
||||||
|
let alpns = vec![b"alknet/test".to_vec(), b"alknet/call".to_vec()];
|
||||||
|
let config = build_rustls_server_config(&identity, &alpns).expect("raw key config builds");
|
||||||
|
assert_eq!(config.alpn_protocols, alpns);
|
||||||
|
assert_eq!(config.max_early_data_size, u32::MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn build_rustls_server_config_self_signed_succeeds() {
|
||||||
|
let identity = TlsIdentity::SelfSigned;
|
||||||
|
let alpns = vec![b"alknet/test".to_vec()];
|
||||||
|
let config =
|
||||||
|
build_rustls_server_config(&identity, &alpns).expect("self-signed config builds");
|
||||||
|
assert_eq!(config.alpn_protocols, alpns);
|
||||||
|
assert_eq!(config.max_early_data_size, u32::MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic(expected = "TlsIdentity::Acme is handled by TlsServerConfig::new_acme")]
|
||||||
|
fn build_rustls_server_config_acme_is_unreachable() {
|
||||||
|
let identity = TlsIdentity::Acme {
|
||||||
|
domains: vec!["example.com".to_string()],
|
||||||
|
cache_dir: std::path::PathBuf::from("/tmp/alknet-acme-test"),
|
||||||
|
directory: AcmeDirectory::Staging,
|
||||||
|
contact: vec!["mailto:dev@example.com".to_string()],
|
||||||
|
};
|
||||||
|
let _ = build_rustls_server_config(&identity, &[]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn build_quinn_server_config_from_rustls_succeeds() {
|
||||||
|
let sk = Ed25519SecretKey::generate();
|
||||||
|
let rustls_config =
|
||||||
|
build_rustls_server_config(&TlsIdentity::RawKey(sk), &[b"alknet/test".to_vec()])
|
||||||
|
.expect("rustls config builds");
|
||||||
|
let config = TlsServerConfig {
|
||||||
|
rustls_config,
|
||||||
|
#[cfg(feature = "acme")]
|
||||||
|
acme_state_handle: None,
|
||||||
|
};
|
||||||
|
let quinn_config = config.for_quinn().expect("quinn config converts");
|
||||||
|
let _ = quinn_config;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn accept_any_cert_verifier_offers_and_does_not_require_client_auth() {
|
||||||
|
use rustls::server::danger::ClientCertVerifier;
|
||||||
|
let verifier = AcceptAnyCertVerifier;
|
||||||
|
assert!(verifier.offer_client_auth());
|
||||||
|
assert!(!verifier.client_auth_mandatory());
|
||||||
|
assert!(verifier.root_hint_subjects().is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn accept_any_cert_verifier_verifies_any_client_cert() {
|
||||||
|
use rustls::pki_types::{CertificateDer, UnixTime};
|
||||||
|
use rustls::server::danger::ClientCertVerifier;
|
||||||
|
let verifier = AcceptAnyCertVerifier;
|
||||||
|
let cert = CertificateDer::from(b"fake-cert-der".to_vec());
|
||||||
|
let result = verifier.verify_client_cert(&cert, &[], UnixTime::now());
|
||||||
|
assert!(
|
||||||
|
result.is_ok(),
|
||||||
|
"AcceptAnyCertVerifier must accept any client cert"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn accept_any_cert_verifier_supported_schemes_are_non_empty() {
|
||||||
|
use rustls::server::danger::ClientCertVerifier;
|
||||||
|
let verifier = AcceptAnyCertVerifier;
|
||||||
|
let schemes = verifier.supported_verify_schemes();
|
||||||
|
assert!(!schemes.is_empty(), "must advertise at least one scheme");
|
||||||
|
assert!(schemes.contains(&rustls::SignatureScheme::ED25519));
|
||||||
|
assert!(schemes.contains(&rustls::SignatureScheme::RSA_PSS_SHA256));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn accept_any_cert_verifier_debug_is_implemented() {
|
||||||
|
let verifier = AcceptAnyCertVerifier;
|
||||||
|
let s = format!("{verifier:?}");
|
||||||
|
assert!(s.contains("AcceptAnyCertVerifier"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn raw_key_cert_resolver_debug_is_implemented() {
|
||||||
|
let sk = Ed25519SecretKey::generate();
|
||||||
|
let resolver = RawKeyCertResolver::new(&sk);
|
||||||
|
let s = format!("{resolver:?}");
|
||||||
|
assert!(s.contains("RawKeyCertResolver"));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -56,3 +56,72 @@ impl rustls::sign::Signer for Ed25519SigningKey {
|
|||||||
rustls::SignatureScheme::ED25519
|
rustls::SignatureScheme::ED25519
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ed25519_signing_key_choose_scheme_returns_some_for_ed25519() {
|
||||||
|
use rustls::sign::SigningKey;
|
||||||
|
let sk = alknet_core::config::Ed25519SecretKey::generate();
|
||||||
|
let signing_key = Ed25519SigningKey::new(sk);
|
||||||
|
let signer = signing_key.choose_scheme(&[rustls::SignatureScheme::ED25519]);
|
||||||
|
assert!(
|
||||||
|
signer.is_some(),
|
||||||
|
"must produce a signer when ED25519 is offered"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ed25519_signing_key_choose_scheme_returns_none_without_ed25519() {
|
||||||
|
use rustls::sign::SigningKey;
|
||||||
|
let sk = alknet_core::config::Ed25519SecretKey::generate();
|
||||||
|
let signing_key = Ed25519SigningKey::new(sk);
|
||||||
|
let signer = signing_key.choose_scheme(&[rustls::SignatureScheme::RSA_PSS_SHA256]);
|
||||||
|
assert!(
|
||||||
|
signer.is_none(),
|
||||||
|
"must not produce a signer when ED25519 is not offered"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ed25519_signing_key_algorithm_is_ed25519() {
|
||||||
|
use rustls::sign::SigningKey;
|
||||||
|
let sk = alknet_core::config::Ed25519SecretKey::generate();
|
||||||
|
let signing_key = Ed25519SigningKey::new(sk);
|
||||||
|
assert_eq!(signing_key.algorithm(), rustls::SignatureAlgorithm::ED25519);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ed25519_signing_key_public_key_returns_spki() {
|
||||||
|
use rustls::sign::SigningKey;
|
||||||
|
let sk = alknet_core::config::Ed25519SecretKey::generate();
|
||||||
|
let signing_key = Ed25519SigningKey::new(sk);
|
||||||
|
let spki = signing_key.public_key();
|
||||||
|
assert!(spki.is_some(), "public_key must return an SPKI");
|
||||||
|
assert!(!spki.unwrap().as_ref().is_empty(), "SPKI must be non-empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ed25519_signing_key_signer_signs_message() {
|
||||||
|
use rustls::sign::SigningKey;
|
||||||
|
let sk = alknet_core::config::Ed25519SecretKey::generate();
|
||||||
|
let signing_key = Ed25519SigningKey::new(sk);
|
||||||
|
let signer = signing_key
|
||||||
|
.choose_scheme(&[rustls::SignatureScheme::ED25519])
|
||||||
|
.expect("ED25519 offered");
|
||||||
|
let message = b"alknet coverage signing test";
|
||||||
|
let sig = signer.sign(message).expect("sign must succeed");
|
||||||
|
assert_eq!(sig.len(), 64, "ed25519 signature must be 64 bytes");
|
||||||
|
assert_eq!(signer.scheme(), rustls::SignatureScheme::ED25519);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ed25519_signing_key_debug_does_not_leak_material() {
|
||||||
|
let sk = alknet_core::config::Ed25519SecretKey::generate();
|
||||||
|
let signing_key = Ed25519SigningKey::new(sk);
|
||||||
|
let dbg = format!("{signing_key:?}");
|
||||||
|
assert!(dbg.contains("Ed25519SigningKey"));
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user