Allow setting the notary public key

This commit is contained in:
Hendrik Eeckhaut
2023-10-30 21:39:45 +01:00
parent a6ed6f180b
commit cb66dc650c
5 changed files with 99 additions and 25 deletions

View File

@@ -1,2 +1,3 @@
pub mod redactedBytesComponent;
pub mod viewFile;
pub mod pem_input;
pub mod redacted_bytes_component;
pub mod view_file;

View File

@@ -0,0 +1,70 @@
use elliptic_curve::pkcs8::DecodePublicKey;
// use gloo::console::log;
use web_sys::HtmlInputElement;
use yew::prelude::*;
#[derive(Properties, Clone, PartialEq)]
pub struct Props {
pub pem_callback: Callback<p256::PublicKey>,
}
// from https://github.com/tlsnotary/notary-server/tree/main/src/fixture/notary/notary.key
// converted with `openssl ec -in notary.key -pubout -outform PEM`
pub const DEFAULT_PEM: &str = "-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEBv36FI4ZFszJa0DQFJ3wWCXvVLFr
cRzMG5kaTeHGoSzDu6cFqx3uEWYpFGo6C0EOUgf+mEgbktLrXocv5yHzKg==
-----END PUBLIC KEY-----";
#[function_component(PemInputComponent)]
pub fn pem_input_component(Props { pem_callback }: &Props) -> Html {
let input_value = use_state(|| DEFAULT_PEM.to_string());
let invalid_input = use_state(|| None);
let oninput = {
let input_value = input_value.clone();
let callback = pem_callback.clone();
let invalid_input = invalid_input.clone();
Callback::from(move |e: InputEvent| {
let input: HtmlInputElement = e.target_unchecked_into();
let value = input.value().trim().to_string();
let result = p256::PublicKey::from_public_key_pem(value.as_str());
match result {
Ok(public_key) => {
input_value.set(value.clone());
invalid_input.set(None);
callback.emit(public_key.clone());
}
Err(err) => {
input_value.set(value.clone());
invalid_input.set(Some(err.to_string()));
// do not emit a false pem here
}
}
})
};
let style = if invalid_input.is_none() {
"text-sm text-white border-gray-600 focus:ring-blue-500 focus:border-blue-500"
} else {
"text-sm text-pink-600 border-pink-500 focus:border-pink-500 focus:ring-pink-500"
};
html! {
<div class={style}>
<details class="p-4 w-5/6" open={false}>
<summary><b>{"Change Notary Public Key:" }</b>{if invalid_input.as_ref().is_some() {""} else {""}}</summary>
<textarea class="block p-2.5 w-full bg-gray-700"
id="pem-input"
rows="4"
value={input_value.to_string()}
oninput={oninput} >
</textarea>
if let Some(x) = invalid_input.as_ref() {
<p>{x}</p>
}
</details>
</div>
}
}

View File

@@ -1,5 +1,4 @@
extern crate base64;
use elliptic_curve::pkcs8::DecodePublicKey;
use std::str;
use web_time::Duration;
@@ -7,41 +6,30 @@ use yew::{function_component, html, Html, Properties};
use tlsn_core::proof::{SessionProof, TlsProof};
use crate::components::redactedBytesComponent::Direction;
use crate::components::redactedBytesComponent::RedactedBytesComponent;
use crate::components::redacted_bytes_component::Direction;
use crate::components::redacted_bytes_component::RedactedBytesComponent;
#[derive(Properties, PartialEq)]
pub struct Props {
pub name: String,
pub file_type: String,
pub data: Vec<u8>,
pub pem: p256::PublicKey,
}
#[function_component]
pub fn ViewFile(props: &Props) -> Html {
fn notary_pubkey() -> p256::PublicKey {
// from https://github.com/tlsnotary/notary-server/tree/main/src/fixture/notary/notary.key
// converted with `openssl ec -in notary.key -pubout -outform PEM`
let pem = "-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEBv36FI4ZFszJa0DQFJ3wWCXvVLFr
cRzMG5kaTeHGoSzDu6cFqx3uEWYpFGo6C0EOUgf+mEgbktLrXocv5yHzKg==
-----END PUBLIC KEY-----";
p256::PublicKey::from_public_key_pem(pem).unwrap()
}
// Verify the session proof against the Notary's public key
fn verify_proof(session: &SessionProof) -> Result<(), String> {
fn verify_proof(session: &SessionProof, pem: p256::PublicKey) -> Result<(), String> {
// This verifies the identity of the server using a default certificate verifier which trusts
// the root certificates from the `webpki-roots` crate.
session
.verify_with_default_cert_verifier(notary_pubkey())
.verify_with_default_cert_verifier(pem)
.map_err(|err| err.to_string())
}
fn parse_tls_proof(json_str: &str) -> Html {
fn parse_tls_proof(json_str: &str, pem: p256::PublicKey) -> Html {
let tls_proof: Result<TlsProof, serde_json::Error> = serde_json::from_str(json_str);
// info!("Parsing");
@@ -57,7 +45,7 @@ cRzMG5kaTeHGoSzDu6cFqx3uEWYpFGo6C0EOUgf+mEgbktLrXocv5yHzKg==
substrings,
} = tls_proof;
let proof_verification = verify_proof(&session);
let proof_verification = verify_proof(&session, pem);
if proof_verification.is_err() {
return html! {
@@ -137,7 +125,7 @@ cRzMG5kaTeHGoSzDu6cFqx3uEWYpFGo6C0EOUgf+mEgbktLrXocv5yHzKg==
<div class="flex-1 flex flex-col justify-center p-4">
<div class="container mx-auto px-4">
if props.file_type.contains("application/json") {
{parse_tls_proof(json_str)}
{parse_tls_proof(json_str, props.pem)}
}
</div>
</div>

View File

@@ -3,12 +3,18 @@ use gloo::file::callbacks::FileReader;
use gloo::file::File;
use std::collections::HashMap;
#[allow(unused_imports)]
use gloo::console::log;
use web_sys::{DragEvent, Event, FileList, HtmlInputElement};
use yew::html::TargetCast;
use yew::{html, Callback, Component, Context, Html, Properties};
use yew::prelude::*;
mod components;
use crate::components::viewFile::ViewFile;
use crate::components::pem_input::PemInputComponent;
use crate::components::pem_input::DEFAULT_PEM;
use crate::components::view_file::ViewFile;
use elliptic_curve::pkcs8::DecodePublicKey;
#[derive(Properties, PartialEq)]
struct FileDetails {
@@ -20,11 +26,13 @@ struct FileDetails {
pub enum Msg {
Loaded(String, String, Vec<u8>),
Files(Vec<File>),
Pem(p256::PublicKey),
}
pub struct App {
readers: HashMap<String, FileReader>,
files: Vec<FileDetails>,
pem: p256::PublicKey,
}
impl Component for App {
@@ -35,6 +43,7 @@ impl Component for App {
Self {
readers: HashMap::default(),
files: Vec::default(),
pem: p256::PublicKey::from_public_key_pem(DEFAULT_PEM).unwrap(),
}
}
@@ -49,6 +58,10 @@ impl Component for App {
self.readers.remove(&file_name);
true
}
Msg::Pem(pem) => {
self.pem = pem;
true
}
Msg::Files(files) => {
for file in files.into_iter() {
let file_name = file.name();
@@ -151,9 +164,11 @@ impl Component for App {
})}
/>
<PemInputComponent pem_callback={ctx.link().callback(|pem| Msg::Pem(pem))}/>
<div>
{for self.files.iter().rev().map(|file| html! {
<ViewFile name={file.name.clone()} file_type={file.file_type.clone()} data={file.data.clone()} />
<ViewFile name={file.name.clone()} file_type={file.file_type.clone()} data={file.data.clone()} pem={self.pem} />
})}
</div>
</div>