More progress and cleanup
This commit is contained in:
@@ -1,19 +1,16 @@
|
|||||||
use axum::Json;
|
|
||||||
use axum::extract::Path;
|
use axum::extract::Path;
|
||||||
use axum::http::StatusCode;
|
use axum::http::StatusCode;
|
||||||
use axum::response::{IntoResponse, Response};
|
use axum::response::{IntoResponse, Response};
|
||||||
use openssl::hash::MessageDigest;
|
use openssl::hash::MessageDigest;
|
||||||
use openssl::sha::Sha256;
|
use openssl::sha::Sha256;
|
||||||
use openssl::symm::Cipher;
|
|
||||||
use rand::Rng;
|
|
||||||
use reqwest::Identity;
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use openssl::pkey::{PKey, Private};
|
use openssl::pkey::{PKey, Private};
|
||||||
use openssl::rsa::Rsa;
|
use openssl::rsa::Rsa;
|
||||||
use openssl::x509::X509;
|
use openssl::x509::{self, X509};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
use url_constructor::UrlConstructor;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
struct ServerCertResponse {
|
struct ServerCertResponse {
|
||||||
@@ -32,63 +29,95 @@ pub struct ServerChallengeResponseResponse {
|
|||||||
pairingsecret: String,
|
pairingsecret: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct ServerCert {
|
||||||
|
cert: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ServerPairingSecret {
|
||||||
|
pairing_secret: Vec<u8>,
|
||||||
|
signature: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
fn get_cert_and_private_key() -> Result<(X509, PKey<Private>)> {
|
fn get_cert_and_private_key() -> Result<(X509, PKey<Private>)> {
|
||||||
let rsa = Rsa::generate(2048)?;
|
let rsa = Rsa::generate(2048)?;
|
||||||
let key_pair = PKey::from_rsa(rsa)?;
|
let key_pair = PKey::from_rsa(rsa)?;
|
||||||
|
|
||||||
let mut cert_builder = X509::builder()?;
|
let mut cert_builder = X509::builder()?;
|
||||||
|
|
||||||
|
let serial_number_u32 = openssl::bn::BigNum::from_u32(0)?;
|
||||||
|
let serial_number = openssl::asn1::Asn1Integer::from_bn(&serial_number_u32)?;
|
||||||
|
|
||||||
|
let now_unix = std::time::SystemTime::now()
|
||||||
|
.duration_since(std::time::UNIX_EPOCH)
|
||||||
|
.expect("Time went backwards")
|
||||||
|
.as_secs()
|
||||||
|
- 1000000;
|
||||||
|
let now = openssl::asn1::Asn1Time::from_unix(now_unix as i64)?;
|
||||||
|
let ten_years_from_now = openssl::asn1::Asn1Time::days_from_now(365 * 10)?;
|
||||||
|
|
||||||
|
let mut x509_name_builder = openssl::x509::X509NameBuilder::new()?;
|
||||||
|
x509_name_builder.append_entry_by_text("CN", "NVIDIA GameStream Client")?;
|
||||||
|
let x509_name = x509_name_builder.build();
|
||||||
|
|
||||||
cert_builder.set_version(2)?;
|
cert_builder.set_version(2)?;
|
||||||
|
cert_builder.set_not_before(&now)?;
|
||||||
|
cert_builder.set_not_after(&ten_years_from_now)?;
|
||||||
cert_builder.set_pubkey(&key_pair)?;
|
cert_builder.set_pubkey(&key_pair)?;
|
||||||
|
cert_builder.set_serial_number(&serial_number)?;
|
||||||
|
cert_builder.set_issuer_name(&x509_name)?;
|
||||||
|
cert_builder.set_subject_name(&x509_name)?;
|
||||||
cert_builder.sign(&key_pair, MessageDigest::sha256())?;
|
cert_builder.sign(&key_pair, MessageDigest::sha256())?;
|
||||||
let cert = cert_builder.build();
|
let cert = cert_builder.build();
|
||||||
Ok((cert, key_pair))
|
Ok((cert, key_pair))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn get_url(base_url: &mut url_constructor::UrlConstructor) -> Result<String> {
|
||||||
|
let mut uuidv2 = [0u8; 16];
|
||||||
|
openssl::rand::rand_bytes(&mut uuidv2)?;
|
||||||
|
let uuidv2_hex = hex::encode(uuidv2);
|
||||||
|
|
||||||
|
let url = base_url.param("uuid", uuidv2_hex).build();
|
||||||
|
println!("Getting url: {url}");
|
||||||
|
|
||||||
|
let mut http_builder = reqwest::Client::builder();
|
||||||
|
http_builder = http_builder.user_agent("Mozilla/5.0");
|
||||||
|
let client = http_builder.build().unwrap();
|
||||||
|
|
||||||
|
let resp = client.get(url).send().await?;
|
||||||
|
let text = resp.text().await?;
|
||||||
|
Ok(text)
|
||||||
|
}
|
||||||
|
|
||||||
async fn get_server_cert(
|
async fn get_server_cert(
|
||||||
mut base_url: url_constructor::UrlConstructor,
|
mut base_url: url_constructor::UrlConstructor,
|
||||||
salt_hex: String,
|
salt_hex: String,
|
||||||
cert_hex: String,
|
cert_hex: String,
|
||||||
) -> Result<ServerCertResponse> {
|
) -> Result<ServerCert> {
|
||||||
// Generate pairing url
|
// Generate pairing url
|
||||||
let url = base_url
|
let url = base_url
|
||||||
.param("phrase", "getservercert")
|
.param("phrase", "getservercert")
|
||||||
.param("salt", &salt_hex)
|
.param("salt", &salt_hex)
|
||||||
.param("clientcert", &cert_hex)
|
.param("clientcert", &cert_hex);
|
||||||
.build();
|
|
||||||
//let url = format!(
|
|
||||||
// "http://{}/pair?uniqueid={}&uuid={}&devicename=roth&updateState=1&phrase=getservercert&salt={}&clientcert={}",
|
|
||||||
// host, "0123456789ABCDEF", "23060a17e4fc40f5a83fee298995dd18", salt_hex, cert_hex,
|
|
||||||
//);
|
|
||||||
println!("url: {url}");
|
|
||||||
|
|
||||||
//let mut identity_data = private_key.private_key_to_pem_pkcs8().unwrap();
|
let text = get_url(url).await?;
|
||||||
//identity_data.extend_from_slice(&cert_pem);
|
let server_cert: ServerCertResponse = serde_xml_rs::from_str(&text)?;
|
||||||
|
|
||||||
//let identity = Identity::from_pem(&identity_data).unwrap();
|
let server_cert_bytes = hex::decode(server_cert.plaincert)?;
|
||||||
//let identity =
|
|
||||||
// Identity::from_pkcs8_pem(&cert_pem, &private_key.private_key_to_pem_pkcs8().unwrap())
|
|
||||||
// .unwrap();
|
|
||||||
|
|
||||||
let mut http_builder = reqwest::Client::builder();
|
Ok(ServerCert {
|
||||||
http_builder = http_builder.user_agent("gamestream-webtransport-proxy");
|
cert: server_cert_bytes,
|
||||||
//http_builder = http_builder.identity(identity);
|
})
|
||||||
let client = http_builder.build().unwrap();
|
|
||||||
|
|
||||||
let resp = client.get(url).send().await?;
|
|
||||||
let text = resp.text().await.unwrap();
|
|
||||||
let server_response: ServerCertResponse = serde_xml_rs::from_str(&text).unwrap();
|
|
||||||
println!("{server_response:?}");
|
|
||||||
Ok(server_response)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_server_challenge(
|
async fn get_server_challenge(
|
||||||
mut base_url: url_constructor::UrlConstructor,
|
mut base_url: url_constructor::UrlConstructor,
|
||||||
aes_key: &[u8],
|
aes_key: &[u8],
|
||||||
) -> Result<ClientChallengeResponse> {
|
) -> Result<ClientChallengeResponse> {
|
||||||
// 3. Generate random challenge
|
|
||||||
let mut challenge_data = [0u8; 16];
|
let mut challenge_data = [0u8; 16];
|
||||||
openssl::rand::rand_bytes(&mut challenge_data)?;
|
openssl::rand::rand_bytes(&mut challenge_data)?;
|
||||||
|
|
||||||
// 4. Encrypt challenge
|
|
||||||
let mut cipher_ctx = openssl::cipher_ctx::CipherCtx::new()?;
|
let mut cipher_ctx = openssl::cipher_ctx::CipherCtx::new()?;
|
||||||
cipher_ctx.encrypt_init(
|
cipher_ctx.encrypt_init(
|
||||||
Some(openssl::cipher::Cipher::aes_128_ecb()),
|
Some(openssl::cipher::Cipher::aes_128_ecb()),
|
||||||
@@ -101,23 +130,17 @@ async fn get_server_challenge(
|
|||||||
cipher_ctx.cipher_update_vec(&challenge_data, &mut challenge_enc)?;
|
cipher_ctx.cipher_update_vec(&challenge_data, &mut challenge_enc)?;
|
||||||
cipher_ctx.cipher_final(&mut challenge_enc)?;
|
cipher_ctx.cipher_final(&mut challenge_enc)?;
|
||||||
|
|
||||||
// 5. Convert to hex
|
|
||||||
let challenge_hex = hex::encode(challenge_enc);
|
let challenge_hex = hex::encode(challenge_enc);
|
||||||
|
|
||||||
let url = base_url.param("clientchallenge", challenge_hex).build();
|
let url = base_url.param("clientchallenge", challenge_hex);
|
||||||
let mut http_builder = reqwest::Client::builder();
|
let text = get_url(url).await?;
|
||||||
http_builder = http_builder.user_agent("gamestream-webtransport-proxy");
|
|
||||||
//http_builder = http_builder.identity(identity);
|
|
||||||
let client = http_builder.build().unwrap();
|
|
||||||
|
|
||||||
let resp = client.get(url).send().await?;
|
|
||||||
let text = resp.text().await?;
|
|
||||||
|
|
||||||
Ok(serde_xml_rs::from_str(&text)?)
|
Ok(serde_xml_rs::from_str(&text)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_challenge_response(
|
fn generate_challenge_response(
|
||||||
client_challenge_response: String,
|
client_challenge_response: String,
|
||||||
|
client_secret_data: &[u8; 16],
|
||||||
aes_key: &[u8],
|
aes_key: &[u8],
|
||||||
cert: &X509,
|
cert: &X509,
|
||||||
) -> Result<String> {
|
) -> Result<String> {
|
||||||
@@ -145,9 +168,6 @@ fn generate_challenge_response(
|
|||||||
)?;
|
)?;
|
||||||
cipher_ctx.cipher_final(&mut client_challenge_response_data)?;
|
cipher_ctx.cipher_final(&mut client_challenge_response_data)?;
|
||||||
|
|
||||||
let mut client_secret_data = [0u8; 16];
|
|
||||||
openssl::rand::rand_bytes(&mut client_secret_data)?;
|
|
||||||
|
|
||||||
// Extract ASN.1 signature from certificate
|
// Extract ASN.1 signature from certificate
|
||||||
let asn_signature = cert.signature();
|
let asn_signature = cert.signature();
|
||||||
let signature_data = asn_signature.as_slice();
|
let signature_data = asn_signature.as_slice();
|
||||||
@@ -157,7 +177,7 @@ fn generate_challenge_response(
|
|||||||
Vec::with_capacity(16 + signature_data.len() + client_secret_data.len());
|
Vec::with_capacity(16 + signature_data.len() + client_secret_data.len());
|
||||||
challenge_response.extend_from_slice(&client_challenge_response_data[32..32 + 16]);
|
challenge_response.extend_from_slice(&client_challenge_response_data[32..32 + 16]);
|
||||||
challenge_response.extend_from_slice(signature_data);
|
challenge_response.extend_from_slice(signature_data);
|
||||||
challenge_response.extend_from_slice(&client_secret_data);
|
challenge_response.extend_from_slice(client_secret_data);
|
||||||
|
|
||||||
let mut hasher = Sha256::new();
|
let mut hasher = Sha256::new();
|
||||||
hasher.update(&challenge_response);
|
hasher.update(&challenge_response);
|
||||||
@@ -184,18 +204,9 @@ async fn send_server_challenge_response(
|
|||||||
mut base_url: url_constructor::UrlConstructor,
|
mut base_url: url_constructor::UrlConstructor,
|
||||||
server_challenge_response: String,
|
server_challenge_response: String,
|
||||||
) -> Result<ServerChallengeResponseResponse> {
|
) -> Result<ServerChallengeResponseResponse> {
|
||||||
let url = base_url
|
let url = base_url.param("serverchallengeresp", server_challenge_response);
|
||||||
.param("serverchallengeresp", server_challenge_response)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
println!("url: {url}");
|
let text = get_url(url).await?;
|
||||||
let mut http_builder = reqwest::Client::builder();
|
|
||||||
http_builder = http_builder.user_agent("gamestream-webtransport-proxy");
|
|
||||||
//http_builder = http_builder.identity(identity);
|
|
||||||
let client = http_builder.build().unwrap();
|
|
||||||
|
|
||||||
let resp = client.get(url).send().await?;
|
|
||||||
let text = resp.text().await?;
|
|
||||||
Ok(serde_xml_rs::from_str(&text)?)
|
Ok(serde_xml_rs::from_str(&text)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -211,31 +222,38 @@ async fn generate_aes_key(salt: [u8; 16], pin: [u8; 4]) -> Vec<u8> {
|
|||||||
|
|
||||||
async fn do_challenge(
|
async fn do_challenge(
|
||||||
base_url: url_constructor::UrlConstructor,
|
base_url: url_constructor::UrlConstructor,
|
||||||
|
client_secret_data: &[u8; 16],
|
||||||
pin: [u8; 4],
|
pin: [u8; 4],
|
||||||
salt: [u8; 16],
|
salt: [u8; 16],
|
||||||
cert: &X509,
|
cert: &X509,
|
||||||
) -> Result<()> {
|
) -> Result<ServerPairingSecret> {
|
||||||
let aes_key = generate_aes_key(salt, pin).await;
|
let aes_key = generate_aes_key(salt, pin).await;
|
||||||
|
|
||||||
let client_challenge_response = get_server_challenge(base_url.clone(), &aes_key).await?;
|
let client_challenge_response = get_server_challenge(base_url.clone(), &aes_key).await?;
|
||||||
println!("{client_challenge_response:?}");
|
println!("{client_challenge_response:?}");
|
||||||
|
|
||||||
let challenge_response =
|
let challenge_response = generate_challenge_response(
|
||||||
generate_challenge_response(client_challenge_response.challengeresponse, &aes_key, cert)?;
|
client_challenge_response.challengeresponse,
|
||||||
println!("{challenge_response:?}");
|
client_secret_data,
|
||||||
|
&aes_key,
|
||||||
|
cert,
|
||||||
|
)?;
|
||||||
|
|
||||||
let server_challenge_response_response =
|
let server_challenge_response_response =
|
||||||
send_server_challenge_response(base_url, challenge_response).await?;
|
send_server_challenge_response(base_url, challenge_response).await?;
|
||||||
println!("{server_challenge_response_response:?}");
|
let pairing_secret_bytes = hex::decode(server_challenge_response_response.pairingsecret)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(ServerPairingSecret {
|
||||||
|
pairing_secret: pairing_secret_bytes[0..16].into(),
|
||||||
|
signature: pairing_secret_bytes[16..].into(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do a pairing operation
|
pub async fn get_base_url(
|
||||||
pub async fn get_pair(Path((host, port)): Path<(String, u16)>) -> Response {
|
host: String,
|
||||||
let unique_id = "0123456789ABCDEF";
|
port: u16,
|
||||||
let uuidv2 = "23060a17e4fc40f5a83fee298995dd18";
|
unique_id: String,
|
||||||
|
) -> url_constructor::UrlConstructor {
|
||||||
let mut base_url = url_constructor::UrlConstructor::new();
|
let mut base_url = url_constructor::UrlConstructor::new();
|
||||||
base_url
|
base_url
|
||||||
.scheme("http")
|
.scheme("http")
|
||||||
@@ -243,14 +261,17 @@ pub async fn get_pair(Path((host, port)): Path<(String, u16)>) -> Response {
|
|||||||
.port(port)
|
.port(port)
|
||||||
.subdir("pair")
|
.subdir("pair")
|
||||||
.param("uniqueid", unique_id)
|
.param("uniqueid", unique_id)
|
||||||
.param("uuid", uuidv2)
|
.param("devicename", "roth") // TODO: what is this roth thing?
|
||||||
.param("devicename", "roth")
|
|
||||||
.param("updateState", "1");
|
.param("updateState", "1");
|
||||||
|
base_url
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn generate_pin() -> [u8; 4] {
|
||||||
let mut pin = [0u8; 4];
|
let mut pin = [0u8; 4];
|
||||||
{
|
{
|
||||||
print!("pairing pin: ");
|
print!("pairing pin: ");
|
||||||
|
|
||||||
|
// TODO: reenable real RNG
|
||||||
let mut rng = rand::rng();
|
let mut rng = rand::rng();
|
||||||
for i in 0..pin.len() {
|
for i in 0..pin.len() {
|
||||||
pin[i] = 5;
|
pin[i] = 5;
|
||||||
@@ -261,6 +282,83 @@ pub async fn get_pair(Path((host, port)): Path<(String, u16)>) -> Response {
|
|||||||
// Print as a four-digit, zero-padded integer
|
// Print as a four-digit, zero-padded integer
|
||||||
println!("");
|
println!("");
|
||||||
}
|
}
|
||||||
|
pin
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn verify_signature(secret: Vec<u8>, signature: Vec<u8>, cert: Vec<u8>) -> Result<()> {
|
||||||
|
let cert_x509 = openssl::x509::X509::from_pem(&cert)?;
|
||||||
|
let cert_pubkey = cert_x509.public_key()?;
|
||||||
|
|
||||||
|
let md = openssl::md::Md::sha256();
|
||||||
|
let mut mdctx = openssl::md_ctx::MdCtx::new()?;
|
||||||
|
|
||||||
|
mdctx.digest_verify_init(Some(md), &cert_pubkey)?;
|
||||||
|
mdctx.digest_verify_update(&secret)?;
|
||||||
|
match mdctx.digest_verify_final(&signature)? {
|
||||||
|
true => Ok(()),
|
||||||
|
false => Err(anyhow::anyhow!(
|
||||||
|
"Signature failed to verify. Are we being MITMed?"
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn create_signature(data: &[u8; 16], private_key: &PKey<Private>) -> Result<Vec<u8>> {
|
||||||
|
let mut signature = Vec::new();
|
||||||
|
|
||||||
|
let md = openssl::md::Md::sha256();
|
||||||
|
let mut mdctx = openssl::md_ctx::MdCtx::new()?;
|
||||||
|
|
||||||
|
mdctx.digest_sign_init(Some(md), private_key)?;
|
||||||
|
mdctx.digest_sign_update(data)?;
|
||||||
|
|
||||||
|
mdctx.digest_sign_final_to_vec(&mut signature)?;
|
||||||
|
|
||||||
|
Ok(signature)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn send_client_pairing_secret(
|
||||||
|
mut base_url: url_constructor::UrlConstructor,
|
||||||
|
client_secret_data: &[u8; 16],
|
||||||
|
private_key: &PKey<Private>,
|
||||||
|
) -> Result<()> {
|
||||||
|
let signature = create_signature(client_secret_data, private_key).await?;
|
||||||
|
|
||||||
|
let mut client_secret = Vec::with_capacity(client_secret_data.len() + signature.len());
|
||||||
|
client_secret.extend_from_slice(client_secret_data);
|
||||||
|
client_secret.extend_from_slice(&signature);
|
||||||
|
|
||||||
|
let client_secret_hex = hex::encode(&client_secret);
|
||||||
|
|
||||||
|
let url = base_url.param("clientpairingsecret", client_secret_hex);
|
||||||
|
|
||||||
|
let text = get_url(url).await?;
|
||||||
|
println!("{text:?}");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_unique_id() -> Result<String> {
|
||||||
|
let mut bytes = [0u8; 8];
|
||||||
|
openssl::rand::rand_bytes(&mut bytes)?;
|
||||||
|
Ok(hex::encode(bytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do a pairing operation
|
||||||
|
pub async fn get_pair(Path((host, port)): Path<(String, u16)>) -> Response {
|
||||||
|
//let unique_id = "0123456789ABCDEF".to_string();
|
||||||
|
//let uuidv2 = "23060a17e4fc40f5a83fee298995dd18".to_string();
|
||||||
|
|
||||||
|
let unique_id = get_unique_id().await.unwrap();
|
||||||
|
|
||||||
|
let base_url = get_base_url(host, port, unique_id).await;
|
||||||
|
|
||||||
|
let pin = generate_pin().await;
|
||||||
|
|
||||||
|
let mut client_secret_data = [0u8; 16];
|
||||||
|
if let Err(e) = openssl::rand::rand_bytes(&mut client_secret_data) {
|
||||||
|
println!("Could not generate client secret data: {e}");
|
||||||
|
return StatusCode::INTERNAL_SERVER_ERROR.into_response();
|
||||||
|
}
|
||||||
|
|
||||||
// Generate certificates
|
// Generate certificates
|
||||||
let (cert, private_key) = match get_cert_and_private_key() {
|
let (cert, private_key) = match get_cert_and_private_key() {
|
||||||
@@ -280,10 +378,46 @@ pub async fn get_pair(Path((host, port)): Path<(String, u16)>) -> Response {
|
|||||||
openssl::rand::rand_bytes(&mut salt).unwrap();
|
openssl::rand::rand_bytes(&mut salt).unwrap();
|
||||||
let salt_hex = hex::encode(salt);
|
let salt_hex = hex::encode(salt);
|
||||||
|
|
||||||
let server_cert_response = get_server_cert(base_url.clone(), salt_hex, cert_hex).await;
|
// Get the server certificate and start the pairing process
|
||||||
|
// This returns once the user has submitted the pin to the
|
||||||
|
// server out of band.
|
||||||
|
let server_cert = match get_server_cert(base_url.clone(), salt_hex, cert_hex).await {
|
||||||
|
Ok(s) => s,
|
||||||
|
Err(e) => {
|
||||||
|
println!("could not get server cert: {e}");
|
||||||
|
return StatusCode::INTERNAL_SERVER_ERROR.into_response();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
println!("{server_cert:?}");
|
||||||
|
|
||||||
if let Err(e) = do_challenge(base_url.clone(), pin, salt, &cert).await {
|
// Do the challenge response process
|
||||||
println!("could not do challenge: {e}");
|
// This returns the pairing secret
|
||||||
|
let server_pairing_secret =
|
||||||
|
match do_challenge(base_url.clone(), &client_secret_data, pin, salt, &cert).await {
|
||||||
|
Ok(s) => s,
|
||||||
|
Err(e) => {
|
||||||
|
println!("could not do challenge: {e}");
|
||||||
|
return StatusCode::INTERNAL_SERVER_ERROR.into_response();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
println!("{server_pairing_secret:?}");
|
||||||
|
|
||||||
|
// Verify the pairing_secret signature
|
||||||
|
if let Err(e) = verify_signature(
|
||||||
|
server_pairing_secret.pairing_secret,
|
||||||
|
server_pairing_secret.signature,
|
||||||
|
server_cert.cert,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
println!("Could not verify signature: {e}");
|
||||||
|
return StatusCode::INTERNAL_SERVER_ERROR.into_response();
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Err(e) =
|
||||||
|
send_client_pairing_secret(base_url.clone(), &client_secret_data, &private_key).await
|
||||||
|
{
|
||||||
|
println!("Could not send client pairing secret: {e}");
|
||||||
return StatusCode::INTERNAL_SERVER_ERROR.into_response();
|
return StatusCode::INTERNAL_SERVER_ERROR.into_response();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user