diff --git a/quiche/Cargo.toml b/quiche/Cargo.toml index 30681fbb49..e34b7d7813 100644 --- a/quiche/Cargo.toml +++ b/quiche/Cargo.toml @@ -64,6 +64,7 @@ mio = "0.6" url = "1" env_logger = "0.9.3" pem = "1.1.0" +boring = { version = "2.0.0" } [lib] crate-type = ["lib", "staticlib", "cdylib"] diff --git a/quiche/examples/.gitignore b/quiche/examples/.gitignore new file mode 100644 index 0000000000..8128fdfbf5 --- /dev/null +++ b/quiche/examples/.gitignore @@ -0,0 +1,2 @@ +webtransport_example.crt +webtransport_example.key diff --git a/quiche/examples/webtransport-server-public/index.html b/quiche/examples/webtransport-server-public/index.html index e9109aaa0d..d2f8ad9ad5 100644 --- a/quiche/examples/webtransport-server-public/index.html +++ b/quiche/examples/webtransport-server-public/index.html @@ -1,4 +1,12 @@ + + + +

+ +

+

Please refer to the console to view the connection process.

+ \ No newline at end of file diff --git a/quiche/examples/webtransport-server-public/index.js b/quiche/examples/webtransport-server-public/index.js index 882b7f803d..8663b3ced3 100644 --- a/quiche/examples/webtransport-server-public/index.js +++ b/quiche/examples/webtransport-server-public/index.js @@ -6,7 +6,7 @@ const startedAt = performance.now(); */ async function startClientTests(args, hashes) { const url = 'https://' + args.hostname + ':' + args.port + '/echo' - console.log('startconnection') + console.log('startconnection123') const hashargs = { ...hashes, serverCertificateHashes: hashes.serverCertificateHashes @@ -103,18 +103,20 @@ async function echoTestsConnection(transport) { } -// edit the next lines for your test setting -startClientTests( - { hostname: '127.0.0.1', port: 4430 }, - { - serverCertificateHashes: [ - // Webtransport Example Cert - { - algorithm: 'sha-256', - value: - "13:C7:66:8F:EB:BA:94:0F:3E:97:2A:B2:3A:4E:CB:89:1D:B5:47:7E:94:FD:44:EA:00:DB:2E:05:81:D2:43:31", - }, - ] - } -) +window.onFingerprintSubmit = () => { + let fingerprint = document.getElementById("fingerprint").value.trim(); + console.log(`fingerprint: "${fingerprint}"`) + + startClientTests( + { hostname: '127.0.0.1', port: 4430 }, + { + serverCertificateHashes: [ + { + algorithm: 'sha-256', + value: fingerprint, + }, + ] + } + ) +} diff --git a/quiche/examples/webtransport-server.rs b/quiche/examples/webtransport-server.rs index c9355f2ab9..09dbc4f67d 100644 --- a/quiche/examples/webtransport-server.rs +++ b/quiche/examples/webtransport-server.rs @@ -33,6 +33,14 @@ use std::net; use std::collections::HashMap; use std::pin::Pin; +use boring::asn1::Asn1Time; +use boring::bn::BigNum; +use boring::bn::MsbOption; +use boring::ec::EcGroup; +use boring::ec::EcKey; +use boring::hash::MessageDigest; +use boring::pkey::PKey; +use boring::x509::extension::BasicConstraints; use env_logger::Env; use quiche::h3::webtransport::ServerSession; use ring::rand::*; @@ -82,20 +90,73 @@ fn main() { ) .unwrap(); - let pem_serialized = - fs::read_to_string("examples/webtransport_example.crt").unwrap(); + let cert_file = "examples/webtransport_example.crt"; + let priv_file = "examples/webtransport_example.key"; + + // WebTransport certs are required to be rotated such that their expiration date does not exceed 10 days into the future. + // + // This is equivalent to: + // openssl req -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 -x509 -sha256 -nodes -out webtransport_example.crt -keyout webtransport_example.key -days 10 + let curve = + &EcGroup::from_curve_name(boring::nid::Nid::X9_62_PRIME256V1).unwrap(); + let key_pair = EcKey::generate(curve).unwrap(); + let key_pair = PKey::from_ec_key(key_pair).unwrap(); + + let mut builder = boring::x509::X509Builder::new().unwrap(); + builder.set_version(0x2).unwrap(); + let serial_number = { + let mut serial = BigNum::new().unwrap(); + serial.rand(159, MsbOption::MAYBE_ZERO, false).unwrap(); + serial.to_asn1_integer().unwrap() + }; + builder.set_serial_number(&serial_number).unwrap(); + builder + .set_not_before(&Asn1Time::days_from_now(0).unwrap()) + .unwrap(); + builder + .set_not_after(&Asn1Time::days_from_now(10).unwrap()) + .unwrap(); + + // Build the x509 issuer and subject names. These are arbitrary. + let mut x509_name = boring::x509::X509NameBuilder::new().unwrap(); + x509_name.append_entry_by_text("C", "US").unwrap(); + x509_name.append_entry_by_text("ST", "CA").unwrap(); + x509_name + .append_entry_by_text("O", "Some organization") + .unwrap(); + + let x509_name = x509_name.build(); + builder.set_issuer_name(&x509_name).unwrap(); + builder.set_subject_name(&x509_name).unwrap(); + + builder.set_pubkey(&key_pair).unwrap(); + + builder + .append_extension( + BasicConstraints::new().critical().ca().build().unwrap(), + ) + .unwrap(); + + builder.sign(&key_pair, MessageDigest::sha256()).unwrap(); + + // Write the new cert and private key to disk + let cert_pem = builder.build().to_pem().unwrap(); + fs::write(cert_file, cert_pem).unwrap(); + let priv_pem = key_pair.private_key_to_pem_pkcs8().unwrap(); + fs::write(priv_file, priv_pem).unwrap(); + + // Generate a SHA256 fingerprint from the cert + let pem_serialized = fs::read_to_string(cert_file).unwrap(); let der_serialized = pem::parse(&pem_serialized).unwrap().contents; let hash = ring::digest::digest(&ring::digest::SHA256, &der_serialized); + info!("Generated fresh private key and certification (expires in no more then 10 days per WebTransport requirements)"); + // Create the configuration for the QUIC connections. let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION).unwrap(); - config - .load_cert_chain_from_pem_file("examples/webtransport_example.crt") - .unwrap(); - config - .load_priv_key_from_pem_file("examples/webtransport_example.key") - .unwrap(); + config.load_cert_chain_from_pem_file(cert_file).unwrap(); + config.load_priv_key_from_pem_file(priv_file).unwrap(); config .set_application_protos(quiche::h3::APPLICATION_PROTOCOL) @@ -122,8 +183,8 @@ fn main() { let mut clients = ClientMap::new(); info!("Server started on {}", server_addr); - info!( - "Server {:?} Fingerprint: {}", + println!( + "Server {:?} Fingerprint:\n{}", hash.algorithm(), hash.as_ref() .into_iter() diff --git a/quiche/examples/webtransport_example.crt b/quiche/examples/webtransport_example.crt deleted file mode 100644 index ba34cab55a..0000000000 --- a/quiche/examples/webtransport_example.crt +++ /dev/null @@ -1,12 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIB2TCCAbCgAwIBAgIJCTT1M3N5Jk3RMAwGCCqGSM49BAMCBQAwZjELMAkGA1UE -BhMCREUxDzANBgNVBAgTBkJlcmxpbjEPMA0GA1UEBxMGQmVybGluMSEwHwYDVQQK -Exh3ZWJ0cmFuc3BvcnQgVGVzdCBTZXJ2ZXIxEjAQBgNVBAMTCTEyNy4wLjAuMTAe -Fw0yMjExMDEwMTMyNThaFw0yMjExMTQwMjMyNThaMGYxCzAJBgNVBAYTAkRFMQ8w -DQYDVQQIEwZCZXJsaW4xDzANBgNVBAcTBkJlcmxpbjEhMB8GA1UEChMYd2VidHJh -bnNwb3J0IFRlc3QgU2VydmVyMRIwEAYDVQQDEwkxMjcuMC4wLjEwWTATBgcqhkjO -PQIBBggqhkjOPQMBBwNCAAQmWf6zwKxa79Yq/0/7i0Z94kgoVW5mZ1wRHpojdrLz -1Fw4ZZz4WBunIeXEQNtbkD42TmyLXZH/7RBgVCZsVE41o0UwQzAMBgNVHRMEBTAD -AQH/MAsGA1UdDwQEAwIC9DAmBgNVHREEHzAdhhtodHRwOi8vZXhhbXBsZS5vcmcv -d2ViaWQjbWUwDAYIKoZIzj0EAwIFAAMVAFtvYmplY3QgQXJyYXlCdWZmZXJd ------END CERTIFICATE----- diff --git a/quiche/examples/webtransport_example.key b/quiche/examples/webtransport_example.key deleted file mode 100644 index 366b3ddf90..0000000000 --- a/quiche/examples/webtransport_example.key +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgqzW3pIvK57oC5F37 -LgFaf+w3YygdLqoJl89apGVINkahRANCAAQmWf6zwKxa79Yq/0/7i0Z94kgoVW5m -Z1wRHpojdrLz1Fw4ZZz4WBunIeXEQNtbkD42TmyLXZH/7RBgVCZsVE41 ------END PRIVATE KEY-----