use alloc::vec;
use alloc::vec::Vec;
use super::common::PcStatus;
use super::{ec, hash, lms, mldsa, mlkem, quic, rsa, tls, x509, xmss};
use crate::der::pem_decode;
fn set_test_alpn(cfg: *mut quic::PcQuicCfg) {
let alpn = b"test\0";
let arr = [alpn.as_ptr() as *const core::ffi::c_char];
let st = unsafe { quic::pc_quic_cfg_set_alpn(cfg, arr.as_ptr(), 1) };
assert_eq!(st, PcStatus::Ok);
}
fn read_out(mut call: impl FnMut(*mut u8, *mut usize) -> PcStatus) -> Vec<u8> {
let mut len = 0usize;
let st = call(core::ptr::null_mut(), &mut len);
if st == PcStatus::Ok {
return Vec::new(); }
assert_eq!(st, PcStatus::BufferTooSmall);
let mut buf = vec![0u8; len];
let st = call(buf.as_mut_ptr(), &mut len);
assert_eq!(st, PcStatus::Ok);
buf.truncate(len);
buf
}
#[test]
fn digest_oneshot_and_streaming() {
let msg = b"abc";
let expected = crate::hash::sha256(msg);
let mut out = [0u8; 64];
let mut len = out.len();
let st = unsafe {
hash::pc_digest(
hash::id::SHA256,
msg.as_ptr(),
msg.len(),
out.as_mut_ptr(),
&mut len,
)
};
assert_eq!(st, PcStatus::Ok);
assert_eq!(&out[..len], &expected);
let h = hash::pc_hash_new(hash::id::SHA256);
assert!(!h.is_null());
unsafe {
assert_eq!(hash::pc_hash_update(h, msg.as_ptr(), 1), PcStatus::Ok);
assert_eq!(hash::pc_hash_update(h, msg[1..].as_ptr(), 2), PcStatus::Ok);
}
let got = read_out(|o, l| unsafe { hash::pc_hash_finish(h, o, l) });
unsafe { hash::pc_hash_free(h) };
assert_eq!(got, expected);
assert!(hash::pc_hash_new(9999).is_null());
}
#[test]
fn hmac_matches() {
let key = b"secret";
let msg = b"message";
let want = crate::hash::HmacSha256::mac(key, msg);
let got = read_out(|o, l| unsafe {
hash::pc_hmac(
hash::id::SHA256,
key.as_ptr(),
key.len(),
msg.as_ptr(),
msg.len(),
o,
l,
)
});
assert_eq!(got, want.as_ref());
}
#[test]
fn rand_fills() {
let mut buf = [0u8; 32];
let st = unsafe { super::rng::pc_rand_bytes(buf.as_mut_ptr(), buf.len()) };
assert_eq!(st, PcStatus::Ok);
assert!(buf.iter().any(|&b| b != 0));
}
#[test]
fn ec_generate_sign_verify() {
let key = ec::pc_ec_generate(ec::curve::P256);
assert!(!key.is_null());
let msg = b"ec message";
let sig = read_out(|o, l| unsafe { ec::pc_ec_sign(key, msg.as_ptr(), msg.len(), o, l) });
let pub_pem = read_out(|o, l| unsafe { ec::pc_ec_public_to_pem(key, o, l) });
let spki = pem_decode(core::str::from_utf8(&pub_pem).unwrap(), "PUBLIC KEY").unwrap();
let ok = unsafe {
ec::pc_ec_verify(
spki.as_ptr(),
spki.len(),
msg.as_ptr(),
msg.len(),
sig.as_ptr(),
sig.len(),
)
};
assert_eq!(ok, PcStatus::Ok);
let bad = b"ec messagX";
let st = unsafe {
ec::pc_ec_verify(
spki.as_ptr(),
spki.len(),
bad.as_ptr(),
bad.len(),
sig.as_ptr(),
sig.len(),
)
};
assert_eq!(st, PcStatus::Verification);
let priv_pem = read_out(|o, l| unsafe { ec::pc_ec_private_to_pem(key, o, l) });
let key2 = unsafe { ec::pc_ec_from_pem(priv_pem.as_ptr(), priv_pem.len()) };
assert!(!key2.is_null());
unsafe {
ec::pc_ec_free(key);
ec::pc_ec_free(key2);
}
}
#[test]
fn rsa_sign_verify_from_pem() {
let pem = crate::test_util::rsa_test_key_a().to_pkcs1_pem();
let key = unsafe { rsa::pc_rsa_from_pem(pem.as_ptr(), pem.len()) };
assert!(!key.is_null());
let msg = b"rsa message";
let sig = read_out(|o, l| unsafe {
rsa::pc_rsa_sign_pkcs1(key, hash::id::SHA256, msg.as_ptr(), msg.len(), o, l)
});
let pub_pem = read_out(|o, l| unsafe { rsa::pc_rsa_public_to_pem(key, o, l) });
let spki = pem_decode(core::str::from_utf8(&pub_pem).unwrap(), "PUBLIC KEY").unwrap();
let ok = unsafe {
rsa::pc_rsa_verify_pkcs1(
spki.as_ptr(),
spki.len(),
hash::id::SHA256,
msg.as_ptr(),
msg.len(),
sig.as_ptr(),
sig.len(),
)
};
assert_eq!(ok, PcStatus::Ok);
unsafe { rsa::pc_rsa_free(key) };
}
#[test]
fn cert_parse_and_verify() {
use crate::x509::{Certificate, DistinguishedName, Time, Validity};
let key = crate::test_util::rsa_test_key_a();
let validity = Validity::new(
Time::utc(2024, 1, 1, 0, 0, 0),
Time::utc(2034, 1, 1, 0, 0, 0),
);
let pem = Certificate::self_signed(
&key,
&DistinguishedName::common_name("ffi cert"),
&validity,
1,
true,
)
.unwrap()
.to_pem();
let cert = unsafe { x509::pc_cert_from_pem(pem.as_ptr(), pem.len()) };
assert!(!cert.is_null());
let spki = read_out(|o, l| unsafe { x509::pc_cert_public_key_spki(cert, o, l) });
assert!(!spki.is_empty());
assert_eq!(unsafe { x509::pc_cert_verify(cert, cert) }, PcStatus::Ok);
unsafe { x509::pc_cert_free(cert) };
}
#[test]
fn pc_mlkem_encaps_accepts_der() {
let k = mlkem::pc_mlkem_generate(mlkem::set_id::ML_KEM_768);
assert!(!k.is_null());
let der = read_out(|o, l| unsafe { mlkem::pc_mlkem_public_to_der(k, o, l) });
assert!(!der.is_empty());
let mut ct = vec![0u8; 1500];
let mut ct_len = ct.len();
let mut ss = [0u8; 32];
let st = unsafe {
mlkem::pc_mlkem_encaps(
mlkem::set_id::ML_KEM_768,
der.as_ptr(),
der.len(),
ct.as_mut_ptr(),
&mut ct_len,
ss.as_mut_ptr(),
)
};
assert_eq!(st, PcStatus::Ok);
assert_eq!(ct_len, 1088);
unsafe { mlkem::pc_mlkem_free(k) };
}
#[test]
fn quic_stream_read_rejects_oversized_out_len() {
use core::ffi::c_char;
let cfg = quic::pc_quic_cfg_new(0);
assert!(!cfg.is_null());
let sni = b"loopback.example\0";
let st = unsafe { quic::pc_quic_cfg_set_server_name(cfg, sni.as_ptr() as *const c_char) };
assert_eq!(st, PcStatus::Ok);
let _ = unsafe { quic::pc_quic_cfg_set_verify_certificates(cfg, 0) };
set_test_alpn(cfg);
let q = unsafe { quic::pc_quic_new(cfg) };
assert!(!q.is_null(), "expected a constructible client");
let mut out_len: usize = usize::MAX;
let mut fin: i32 = 0;
let st =
unsafe { quic::pc_quic_stream_read(q, 0, core::ptr::null_mut(), &mut out_len, &mut fin) };
assert_eq!(st, PcStatus::BufferTooSmall);
assert_eq!(out_len, 1 << 20, "out_len must report the 1 MiB cap");
unsafe { quic::pc_quic_free(q) };
unsafe { quic::pc_quic_cfg_free(cfg) };
}
#[test]
fn dtls_cookie_secret_rejects_wrong_length() {
let cfg = tls::pc_tls_cfg_new(1, 0xFEFD_u32 as i32);
assert!(!cfg.is_null());
let ok_secret = [0xa5u8; 32];
let st =
unsafe { tls::pc_dtls_cfg_set_cookie_secret(cfg, ok_secret.as_ptr(), ok_secret.len()) };
assert_eq!(st, PcStatus::Ok);
let short = [0u8; 31];
let st = unsafe { tls::pc_dtls_cfg_set_cookie_secret(cfg, short.as_ptr(), short.len()) };
assert_eq!(st, PcStatus::Unsupported);
let long = [0u8; 33];
let st = unsafe { tls::pc_dtls_cfg_set_cookie_secret(cfg, long.as_ptr(), long.len()) };
assert_eq!(st, PcStatus::Unsupported);
let st = unsafe { tls::pc_dtls_cfg_set_cookie_secret(cfg, core::ptr::null(), 32) };
assert_eq!(st, PcStatus::NullPointer);
unsafe { tls::pc_tls_cfg_free(cfg) };
}
#[test]
fn quic_set_peer_addr_rejects_wrong_length() {
use core::ffi::c_char;
let cfg = quic::pc_quic_cfg_new(0);
assert!(!cfg.is_null());
let sni = b"loopback.example\0";
let st = unsafe { quic::pc_quic_cfg_set_server_name(cfg, sni.as_ptr() as *const c_char) };
assert_eq!(st, PcStatus::Ok);
let _ = unsafe { quic::pc_quic_cfg_set_verify_certificates(cfg, 0) };
set_test_alpn(cfg);
let q = unsafe { quic::pc_quic_new(cfg) };
assert!(!q.is_null());
let v4mapped: [u8; 16] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 127, 0, 0, 1];
let st = unsafe { quic::pc_quic_set_peer_addr(q, v4mapped.as_ptr(), 16, 4433) };
assert_eq!(st, PcStatus::Ok);
let v4: [u8; 4] = [127, 0, 0, 1];
let st = unsafe { quic::pc_quic_set_peer_addr(q, v4.as_ptr(), 4, 4433) };
assert_eq!(st, PcStatus::Unsupported);
let st = unsafe { quic::pc_quic_set_peer_addr(q, core::ptr::null(), 0, 4433) };
assert_eq!(st, PcStatus::Unsupported);
let st = unsafe { quic::pc_quic_set_peer_addr(q, core::ptr::null(), 16, 4433) };
assert_eq!(st, PcStatus::NullPointer);
unsafe { quic::pc_quic_free(q) };
unsafe { quic::pc_quic_cfg_free(cfg) };
}
#[test]
fn mldsa_verify_rejects_set_mismatch() {
let k = mldsa::pc_mldsa_generate(mldsa::set_id::ML_DSA_44);
assert!(!k.is_null());
let msg = b"mldsa set pinning";
let sig = read_out(|o, l| unsafe { mldsa::pc_mldsa_sign(k, msg.as_ptr(), msg.len(), o, l) });
let pub_pem = read_out(|o, l| unsafe { mldsa::pc_mldsa_public_to_pem(k, o, l) });
let spki = pem_decode(core::str::from_utf8(&pub_pem).unwrap(), "PUBLIC KEY").unwrap();
let st = unsafe {
mldsa::pc_mldsa_verify(
mldsa::set_id::ML_DSA_44,
spki.as_ptr(),
spki.len(),
msg.as_ptr(),
msg.len(),
sig.as_ptr(),
sig.len(),
)
};
assert_eq!(st, PcStatus::Ok);
for set in [mldsa::set_id::ML_DSA_65, mldsa::set_id::ML_DSA_87, 999] {
let st = unsafe {
mldsa::pc_mldsa_verify(
set,
spki.as_ptr(),
spki.len(),
msg.as_ptr(),
msg.len(),
sig.as_ptr(),
sig.len(),
)
};
assert_eq!(
st,
PcStatus::Unsupported,
"set {set} must not verify under a 44 key"
);
}
unsafe { mldsa::pc_mldsa_free(k) };
}
#[test]
fn lms_sign_size_query_does_not_burn_a_key() {
let msg = b"lms size-query message";
for ots in [1i32, 2, 3, 4] {
let k = lms::pc_lms_generate(5 , ots);
assert!(!k.is_null());
let state = |k| read_out(|o, l| unsafe { lms::pc_lms_private_to_bytes(k, o, l) });
let before = state(k);
let mut need = 0usize;
let st = unsafe {
lms::pc_lms_sign(k, msg.as_ptr(), msg.len(), core::ptr::null_mut(), &mut need)
};
assert_eq!(st, PcStatus::BufferTooSmall);
assert!(need > 0);
assert_eq!(
before,
state(k),
"size query must not consume a one-time key"
);
let mut small = vec![0u8; need - 1];
let mut cap = small.len();
let st =
unsafe { lms::pc_lms_sign(k, msg.as_ptr(), msg.len(), small.as_mut_ptr(), &mut cap) };
assert_eq!(st, PcStatus::BufferTooSmall);
assert_eq!(cap, need);
assert_eq!(
before,
state(k),
"too-small sign must not consume a one-time key"
);
let mut sig = vec![0u8; need];
let mut cap = need;
let st =
unsafe { lms::pc_lms_sign(k, msg.as_ptr(), msg.len(), sig.as_mut_ptr(), &mut cap) };
assert_eq!(st, PcStatus::Ok);
assert_eq!(
cap, need,
"predicted LMS signature length != actual (ots {ots})"
);
assert_ne!(before, state(k), "successful sign must advance the state");
let pk = read_out(|o, l| unsafe { lms::pc_lms_public_to_bytes(k, o, l) });
let st = unsafe {
lms::pc_lms_verify(
pk.as_ptr(),
pk.len(),
msg.as_ptr(),
msg.len(),
sig.as_ptr(),
cap,
)
};
assert_eq!(st, PcStatus::Ok);
unsafe { lms::pc_lms_free(k) };
}
}
#[test]
fn hss_sign_size_query_does_not_burn_a_key() {
let msg = b"hss size-query message";
for levels in [1usize, 2] {
let k = lms::pc_hss_generate(levels, 5 , 3 );
assert!(!k.is_null());
let state = |k| read_out(|o, l| unsafe { lms::pc_hss_private_to_bytes(k, o, l) });
let before = state(k);
let mut need = 0usize;
let st = unsafe {
lms::pc_hss_sign(k, msg.as_ptr(), msg.len(), core::ptr::null_mut(), &mut need)
};
assert_eq!(st, PcStatus::BufferTooSmall);
assert!(need > 0);
assert_eq!(
before,
state(k),
"size query must not consume a one-time key"
);
let mut small = vec![0u8; need - 1];
let mut cap = small.len();
let st =
unsafe { lms::pc_hss_sign(k, msg.as_ptr(), msg.len(), small.as_mut_ptr(), &mut cap) };
assert_eq!(st, PcStatus::BufferTooSmall);
assert_eq!(cap, need);
assert_eq!(
before,
state(k),
"too-small sign must not consume a one-time key"
);
let mut sig = vec![0u8; need];
let mut cap = need;
let st =
unsafe { lms::pc_hss_sign(k, msg.as_ptr(), msg.len(), sig.as_mut_ptr(), &mut cap) };
assert_eq!(st, PcStatus::Ok);
assert_eq!(
cap, need,
"predicted HSS signature length != actual (L = {levels})"
);
assert_ne!(before, state(k), "successful sign must advance the state");
let pk = read_out(|o, l| unsafe { lms::pc_hss_public_to_bytes(k, o, l) });
let st = unsafe {
lms::pc_hss_verify(
pk.as_ptr(),
pk.len(),
msg.as_ptr(),
msg.len(),
sig.as_ptr(),
cap,
)
};
assert_eq!(st, PcStatus::Ok);
unsafe { lms::pc_hss_free(k) };
}
}
#[test]
fn xmss_sign_size_query_does_not_burn_a_key() {
let msg = b"xmss size-query message";
let k = xmss::pc_xmss_generate(1 );
assert!(!k.is_null());
let state = |k| read_out(|o, l| unsafe { xmss::pc_xmss_private_to_bytes(k, o, l) });
let before = state(k);
let mut need = 0usize;
let st =
unsafe { xmss::pc_xmss_sign(k, msg.as_ptr(), msg.len(), core::ptr::null_mut(), &mut need) };
assert_eq!(st, PcStatus::BufferTooSmall);
assert!(need > 0);
assert_eq!(
before,
state(k),
"size query must not consume a one-time key"
);
let mut small = vec![0u8; need - 1];
let mut cap = small.len();
let st =
unsafe { xmss::pc_xmss_sign(k, msg.as_ptr(), msg.len(), small.as_mut_ptr(), &mut cap) };
assert_eq!(st, PcStatus::BufferTooSmall);
assert_eq!(cap, need);
assert_eq!(
before,
state(k),
"too-small sign must not consume a one-time key"
);
let mut sig = vec![0u8; need];
let mut cap = need;
let st = unsafe { xmss::pc_xmss_sign(k, msg.as_ptr(), msg.len(), sig.as_mut_ptr(), &mut cap) };
assert_eq!(st, PcStatus::Ok);
assert_eq!(cap, need, "predicted XMSS signature length != actual");
assert_ne!(before, state(k), "successful sign must advance the state");
let pk = read_out(|o, l| unsafe { xmss::pc_xmss_public_to_bytes(k, o, l) });
let st = unsafe {
xmss::pc_xmss_verify(
pk.as_ptr(),
pk.len(),
msg.as_ptr(),
msg.len(),
sig.as_ptr(),
cap,
)
};
assert_eq!(st, PcStatus::Ok);
unsafe { xmss::pc_xmss_free(k) };
}
#[test]
fn xmssmt_sign_size_query_does_not_burn_a_key() {
let msg = b"xmssmt size-query message";
let k = xmss::pc_xmssmt_generate(1 );
assert!(!k.is_null());
let state = |k| read_out(|o, l| unsafe { xmss::pc_xmssmt_private_to_bytes(k, o, l) });
let before = state(k);
let mut need = 0usize;
let st = unsafe {
xmss::pc_xmssmt_sign(k, msg.as_ptr(), msg.len(), core::ptr::null_mut(), &mut need)
};
assert_eq!(st, PcStatus::BufferTooSmall);
assert!(need > 0);
assert_eq!(
before,
state(k),
"size query must not consume a one-time key"
);
let mut small = vec![0u8; need - 1];
let mut cap = small.len();
let st =
unsafe { xmss::pc_xmssmt_sign(k, msg.as_ptr(), msg.len(), small.as_mut_ptr(), &mut cap) };
assert_eq!(st, PcStatus::BufferTooSmall);
assert_eq!(cap, need);
assert_eq!(
before,
state(k),
"too-small sign must not consume a one-time key"
);
let mut sig = vec![0u8; need];
let mut cap = need;
let st =
unsafe { xmss::pc_xmssmt_sign(k, msg.as_ptr(), msg.len(), sig.as_mut_ptr(), &mut cap) };
assert_eq!(st, PcStatus::Ok);
assert_eq!(cap, need, "predicted XMSS^MT signature length != actual");
assert_ne!(before, state(k), "successful sign must advance the state");
let pk = read_out(|o, l| unsafe { xmss::pc_xmssmt_public_to_bytes(k, o, l) });
let st = unsafe {
xmss::pc_xmssmt_verify(
pk.as_ptr(),
pk.len(),
msg.as_ptr(),
msg.len(),
sig.as_ptr(),
cap,
)
};
assert_eq!(st, PcStatus::Ok);
unsafe { xmss::pc_xmssmt_free(k) };
}
fn loopback_identity() -> (alloc::string::String, alloc::string::String) {
use crate::ec::{BoxedEcdsaPrivateKey, CurveId};
use crate::x509::{CertSigner, Certificate, DistinguishedName, Time, Validity};
let mut rng =
crate::rng::HmacDrbg::<crate::hash::Sha256>::new(b"ffi-loopback-identity", b"nonce", &[]);
let key = BoxedEcdsaPrivateKey::generate(CurveId::P256, &mut rng);
let name = DistinguishedName::common_name("loopback.example");
let validity = Validity::new(
Time::utc(2024, 1, 1, 0, 0, 0),
Time::utc(2044, 1, 1, 0, 0, 0),
);
let cert = Certificate::self_signed_general(
&CertSigner::Ecdsa(&key),
&name,
&validity,
1,
false,
&["loopback.example"],
)
.unwrap();
(cert.to_pem(), key.to_sec1_pem())
}
unsafe fn pump_wire(from: *mut tls::PcTls, to: *mut tls::PcTls) {
loop {
let mut len = 0usize;
let st = unsafe { tls::pc_tls_pop(from, core::ptr::null_mut(), &mut len) };
if st == PcStatus::Ok {
assert_eq!(len, 0);
break;
}
assert_eq!(st, PcStatus::BufferTooSmall);
assert!(len > 0);
let mut buf = vec![0u8; len];
let mut cap = len;
let st = unsafe { tls::pc_tls_pop(from, buf.as_mut_ptr(), &mut cap) };
assert_eq!(st, PcStatus::Ok);
assert_eq!(cap, len, "retry must deliver exactly the queried bytes");
let mut consumed = 0usize;
let st = unsafe { tls::pc_tls_feed(to, buf.as_ptr(), cap, &mut consumed) };
assert_eq!(st, PcStatus::Ok);
assert_eq!(consumed, cap);
}
}
#[test]
fn tls_pop_and_recv_too_small_are_non_destructive() {
let (chain_pem, key_pem) = loopback_identity();
let scfg = tls::pc_tls_cfg_new(1 , 0x0304);
assert!(!scfg.is_null());
let st = unsafe {
tls::pc_tls_cfg_set_certificate(
scfg,
chain_pem.as_ptr(),
chain_pem.len(),
key_pem.as_ptr(),
key_pem.len(),
)
};
assert_eq!(st, PcStatus::Ok);
let server = unsafe { tls::pc_tls_new(scfg) };
unsafe { tls::pc_tls_cfg_free(scfg) };
assert!(!server.is_null());
let ccfg = tls::pc_tls_cfg_new(0 , 0x0304);
assert!(!ccfg.is_null());
unsafe {
assert_eq!(
tls::pc_tls_cfg_set_verify_certificates(ccfg, 0),
PcStatus::Ok
);
let sni = b"loopback.example\0";
assert_eq!(
tls::pc_tls_cfg_set_server_name(ccfg, sni.as_ptr() as *const core::ffi::c_char),
PcStatus::Ok
);
}
let client = unsafe { tls::pc_tls_new(ccfg) };
unsafe { tls::pc_tls_cfg_free(ccfg) };
assert!(!client.is_null());
for _ in 0..20 {
unsafe {
let _ = tls::pc_tls_handshake(client);
pump_wire(client, server);
let _ = tls::pc_tls_handshake(server);
pump_wire(server, client);
}
if unsafe { tls::pc_tls_is_handshake_complete(client) } == 1
&& unsafe { tls::pc_tls_is_handshake_complete(server) } == 1
{
break;
}
}
assert_eq!(unsafe { tls::pc_tls_is_handshake_complete(client) }, 1);
assert_eq!(unsafe { tls::pc_tls_is_handshake_complete(server) }, 1);
let msg = b"pop/recv must not eat plaintext";
let st = unsafe { tls::pc_tls_send(server, msg.as_ptr(), msg.len()) };
assert_eq!(st, PcStatus::Ok);
unsafe { pump_wire(server, client) };
let mut need = 0usize;
let st = unsafe { tls::pc_tls_recv(client, core::ptr::null_mut(), &mut need) };
assert_eq!(st, PcStatus::BufferTooSmall);
assert_eq!(need, msg.len());
let mut small = [0u8; 1];
let mut cap = small.len();
let st = unsafe { tls::pc_tls_recv(client, small.as_mut_ptr(), &mut cap) };
assert_eq!(st, PcStatus::BufferTooSmall);
assert_eq!(cap, msg.len());
let mut buf = vec![0u8; need];
let mut cap = need;
let st = unsafe { tls::pc_tls_recv(client, buf.as_mut_ptr(), &mut cap) };
assert_eq!(st, PcStatus::Ok);
assert_eq!(&buf[..cap], msg);
let mut cap = 0usize;
let st = unsafe { tls::pc_tls_recv(client, core::ptr::null_mut(), &mut cap) };
assert_eq!(st, PcStatus::Ok);
assert_eq!(cap, 0);
unsafe {
tls::pc_tls_free(client);
tls::pc_tls_free(server);
}
}
#[test]
fn quic_pop_datagram_too_small_is_non_destructive() {
let cfg = quic::pc_quic_cfg_new(0 );
assert!(!cfg.is_null());
unsafe {
assert_eq!(
quic::pc_quic_cfg_set_verify_certificates(cfg, 0),
PcStatus::Ok
);
let sni = b"loopback.example\0";
assert_eq!(
quic::pc_quic_cfg_set_server_name(cfg, sni.as_ptr() as *const core::ffi::c_char),
PcStatus::Ok
);
}
set_test_alpn(cfg);
let q = unsafe { quic::pc_quic_new(cfg) };
unsafe { quic::pc_quic_cfg_free(cfg) };
assert!(!q.is_null());
let mut need = 0usize;
let st = unsafe { quic::pc_quic_pop_datagram(q, core::ptr::null_mut(), &mut need) };
assert_eq!(st, PcStatus::BufferTooSmall);
assert!(need > 0);
let mut small = [0u8; 8];
let mut cap = small.len();
let st = unsafe { quic::pc_quic_pop_datagram(q, small.as_mut_ptr(), &mut cap) };
assert_eq!(st, PcStatus::BufferTooSmall);
assert_eq!(cap, need);
let mut buf = vec![0u8; need];
let mut cap = need;
let st = unsafe { quic::pc_quic_pop_datagram(q, buf.as_mut_ptr(), &mut cap) };
assert_eq!(st, PcStatus::Ok);
assert_eq!(cap, need);
assert_ne!(buf[0] & 0x80, 0, "expected a long-header packet");
unsafe { quic::pc_quic_free(q) };
}
#[test]
fn buffer_too_small_reports_length() {
let msg = b"abc";
let mut len = 0usize;
let st = unsafe {
hash::pc_digest(
hash::id::SHA256,
msg.as_ptr(),
msg.len(),
core::ptr::null_mut(),
&mut len,
)
};
assert_eq!(st, PcStatus::BufferTooSmall);
assert_eq!(len, 32);
}