Derive the PQ parameters from the classical resolver key seed and the provider signing key, reusing the classical window's serial and dates.
(
provider_kp: &SignKeyPair,
resolver_sk_seed: &[u8; 32],
serial: u32,
ts_start: u32,
ts_end: u32,
)
| 47 | /// Derive the PQ parameters from the classical resolver key seed and the |
| 48 | /// provider signing key, reusing the classical window's serial and dates. |
| 49 | fn derive( |
| 50 | provider_kp: &SignKeyPair, |
| 51 | resolver_sk_seed: &[u8; 32], |
| 52 | serial: u32, |
| 53 | ts_start: u32, |
| 54 | ts_end: u32, |
| 55 | ) -> Self { |
| 56 | let mut seed_input = Vec::with_capacity(19 + 32); |
| 57 | seed_input.extend_from_slice(b"DNSCrypt-PQ-seed-v1"); |
| 58 | seed_input.extend_from_slice(resolver_sk_seed); |
| 59 | let xwing_seed = pq::sha256(&seed_input); |
| 60 | let keypair = pq::XWingKeyPair::from_seed(xwing_seed); |
| 61 | let resolver_pk = keypair.public_key_bytes(); |
| 62 | |
| 63 | let mut client_magic = [0u8; 8]; |
| 64 | client_magic.copy_from_slice(&pq::sha256(&resolver_pk)[..8]); |
| 65 | if client_magic[..7] == [0u8; 7] || client_magic == pq::PQ_RESUME_MAGIC { |
| 66 | client_magic[0] ^= 0xff; |
| 67 | } |
| 68 | |
| 69 | let extensions = pq::profile_extension(); |
| 70 | let serial_be = serial.to_be_bytes(); |
| 71 | let ts_start_be = ts_start.to_be_bytes(); |
| 72 | let ts_end_be = ts_end.to_be_bytes(); |
| 73 | |
| 74 | let mut signed = Vec::with_capacity(pq::XWING_PK_SIZE + 8 + 4 + 4 + 4 + extensions.len()); |
| 75 | signed.extend_from_slice(&resolver_pk); |
| 76 | signed.extend_from_slice(&client_magic); |
| 77 | signed.extend_from_slice(&serial_be); |
| 78 | signed.extend_from_slice(&ts_start_be); |
| 79 | signed.extend_from_slice(&ts_end_be); |
| 80 | signed.extend_from_slice(&extensions); |
| 81 | let signature = provider_kp.sk.sign(&signed); |
| 82 | |
| 83 | let mut cert_bytes = Vec::with_capacity(PQ_CERT_LEN); |
| 84 | cert_bytes.extend_from_slice(&[0x44, 0x4e, 0x53, 0x43]); |
| 85 | cert_bytes.extend_from_slice(&pq::PQ_ES_VERSION); |
| 86 | cert_bytes.extend_from_slice(&[0x00, 0x00]); |
| 87 | cert_bytes.extend_from_slice(signature.as_bytes()); |
| 88 | cert_bytes.extend_from_slice(&signed); |
| 89 | debug_assert_eq!(cert_bytes.len(), PQ_CERT_LEN); |
| 90 | |
| 91 | // The HKDF context and the extension hash are fixed for the lifetime of |
| 92 | // a certificate window, so derive them once here rather than on every |
| 93 | // query. |
| 94 | let cert_context = pq::cert_context( |
| 95 | &pq::PQ_ES_VERSION, |
| 96 | &[0x00, 0x00], |
| 97 | &resolver_pk, |
| 98 | &client_magic, |
| 99 | &serial_be, |
| 100 | &ts_start_be, |
| 101 | &ts_end_be, |
| 102 | &extensions, |
| 103 | ); |
| 104 | let profile_extension_hash = pq::sha256(&extensions); |
| 105 | |
| 106 | PqParams { |
nothing calls this directly
no test coverage detected