203 lines
7.2 KiB
Rust
203 lines
7.2 KiB
Rust
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
extern crate nserror;
|
|
extern crate ohttp;
|
|
extern crate rand;
|
|
extern crate thin_vec;
|
|
#[macro_use]
|
|
extern crate xpcom;
|
|
|
|
use nserror::{nsresult, NS_ERROR_FAILURE, NS_ERROR_NOT_AVAILABLE, NS_OK};
|
|
use ohttp::hpke::{Aead, Kdf, Kem};
|
|
use ohttp::{
|
|
ClientRequest, ClientResponse, KeyConfig, KeyId, Server, ServerResponse, SymmetricSuite,
|
|
};
|
|
use thin_vec::ThinVec;
|
|
use xpcom::interfaces::{
|
|
nsIObliviousHttpClientRequest, nsIObliviousHttpClientResponse, nsIObliviousHttpServer,
|
|
nsIObliviousHttpServerResponse,
|
|
};
|
|
use xpcom::{xpcom_method, RefPtr};
|
|
|
|
use std::cell::RefCell;
|
|
|
|
#[xpcom(implement(nsIObliviousHttpClientResponse), atomic)]
|
|
struct ObliviousHttpClientResponse {
|
|
response: RefCell<Option<ClientResponse>>,
|
|
}
|
|
|
|
impl ObliviousHttpClientResponse {
|
|
xpcom_method!(decapsulate => Decapsulate(enc_response: *const ThinVec<u8>) -> ThinVec<u8>);
|
|
fn decapsulate(&self, enc_response: &ThinVec<u8>) -> Result<ThinVec<u8>, nsresult> {
|
|
let response = self
|
|
.response
|
|
.borrow_mut()
|
|
.take()
|
|
.ok_or(NS_ERROR_NOT_AVAILABLE)?;
|
|
let decapsulated = response
|
|
.decapsulate(enc_response)
|
|
.map_err(|_| NS_ERROR_FAILURE)?;
|
|
Ok(decapsulated.into_iter().collect())
|
|
}
|
|
}
|
|
|
|
#[xpcom(implement(nsIObliviousHttpClientRequest), atomic)]
|
|
struct ObliviousHttpClientRequest {
|
|
enc_request: Vec<u8>,
|
|
response: RefPtr<nsIObliviousHttpClientResponse>,
|
|
}
|
|
|
|
impl ObliviousHttpClientRequest {
|
|
xpcom_method!(get_enc_request => GetEncRequest() -> ThinVec<u8>);
|
|
fn get_enc_request(&self) -> Result<ThinVec<u8>, nsresult> {
|
|
Ok(self.enc_request.clone().into_iter().collect())
|
|
}
|
|
|
|
xpcom_method!(get_response => GetResponse() -> *const nsIObliviousHttpClientResponse);
|
|
fn get_response(&self) -> Result<RefPtr<nsIObliviousHttpClientResponse>, nsresult> {
|
|
Ok(self.response.clone())
|
|
}
|
|
}
|
|
|
|
#[xpcom(implement(nsIObliviousHttpServerResponse), atomic)]
|
|
struct ObliviousHttpServerResponse {
|
|
request: Vec<u8>,
|
|
server_response: RefCell<Option<ServerResponse>>,
|
|
}
|
|
|
|
impl ObliviousHttpServerResponse {
|
|
xpcom_method!(get_request => GetRequest() -> ThinVec<u8>);
|
|
fn get_request(&self) -> Result<ThinVec<u8>, nsresult> {
|
|
Ok(self.request.clone().into_iter().collect())
|
|
}
|
|
|
|
xpcom_method!(encapsulate => Encapsulate(response: *const ThinVec<u8>) -> ThinVec<u8>);
|
|
fn encapsulate(&self, response: &ThinVec<u8>) -> Result<ThinVec<u8>, nsresult> {
|
|
let server_response = self
|
|
.server_response
|
|
.borrow_mut()
|
|
.take()
|
|
.ok_or(NS_ERROR_NOT_AVAILABLE)?;
|
|
Ok(server_response
|
|
.encapsulate(response)
|
|
.map_err(|_| NS_ERROR_FAILURE)?
|
|
.into_iter()
|
|
.collect())
|
|
}
|
|
}
|
|
|
|
#[xpcom(implement(nsIObliviousHttpServer), atomic)]
|
|
struct ObliviousHttpServer {
|
|
server: RefCell<Server>,
|
|
}
|
|
|
|
impl ObliviousHttpServer {
|
|
xpcom_method!(get_encoded_config => GetEncodedConfig() -> ThinVec<u8>);
|
|
fn get_encoded_config(&self) -> Result<ThinVec<u8>, nsresult> {
|
|
let server = self.server.borrow_mut();
|
|
Ok(server
|
|
.config()
|
|
.encode()
|
|
.map_err(|_| NS_ERROR_FAILURE)?
|
|
.into_iter()
|
|
.collect())
|
|
}
|
|
|
|
xpcom_method!(decapsulate => Decapsulate(enc_request: *const ThinVec<u8>) -> *const nsIObliviousHttpServerResponse);
|
|
fn decapsulate(
|
|
&self,
|
|
enc_request: &ThinVec<u8>,
|
|
) -> Result<RefPtr<nsIObliviousHttpServerResponse>, nsresult> {
|
|
let server = self.server.borrow_mut();
|
|
let (request, server_response) = server
|
|
.decapsulate(enc_request)
|
|
.map_err(|_| NS_ERROR_FAILURE)?;
|
|
let oblivious_http_server_response =
|
|
ObliviousHttpServerResponse::allocate(InitObliviousHttpServerResponse {
|
|
request,
|
|
server_response: RefCell::new(Some(server_response)),
|
|
});
|
|
oblivious_http_server_response
|
|
.query_interface::<nsIObliviousHttpServerResponse>()
|
|
.ok_or(NS_ERROR_FAILURE)
|
|
}
|
|
}
|
|
|
|
#[xpcom(implement(nsIObliviousHttp), atomic)]
|
|
struct ObliviousHttp {}
|
|
|
|
impl ObliviousHttp {
|
|
xpcom_method!(encapsulate_request => EncapsulateRequest(encoded_config: *const ThinVec<u8>,
|
|
request: *const ThinVec<u8>) -> *const nsIObliviousHttpClientRequest);
|
|
fn encapsulate_request(
|
|
&self,
|
|
encoded_config: &ThinVec<u8>,
|
|
request: &ThinVec<u8>,
|
|
) -> Result<RefPtr<nsIObliviousHttpClientRequest>, nsresult> {
|
|
ohttp::init();
|
|
|
|
let client =
|
|
ClientRequest::from_encoded_config(encoded_config).map_err(|_| NS_ERROR_FAILURE)?;
|
|
let (enc_request, response) = client.encapsulate(request).map_err(|_| NS_ERROR_FAILURE)?;
|
|
let oblivious_http_client_response =
|
|
ObliviousHttpClientResponse::allocate(InitObliviousHttpClientResponse {
|
|
response: RefCell::new(Some(response)),
|
|
});
|
|
let response = oblivious_http_client_response
|
|
.query_interface::<nsIObliviousHttpClientResponse>()
|
|
.ok_or(NS_ERROR_FAILURE)?;
|
|
let oblivious_http_client_request =
|
|
ObliviousHttpClientRequest::allocate(InitObliviousHttpClientRequest {
|
|
enc_request,
|
|
response,
|
|
});
|
|
oblivious_http_client_request
|
|
.query_interface::<nsIObliviousHttpClientRequest>()
|
|
.ok_or(NS_ERROR_FAILURE)
|
|
}
|
|
|
|
xpcom_method!(server => Server() -> *const nsIObliviousHttpServer);
|
|
fn server(&self) -> Result<RefPtr<nsIObliviousHttpServer>, nsresult> {
|
|
ohttp::init();
|
|
|
|
let key_id: KeyId = rand::random::<u8>();
|
|
let kem: Kem = Kem::X25519Sha256;
|
|
let symmetric = vec![
|
|
SymmetricSuite::new(Kdf::HkdfSha256, Aead::Aes128Gcm),
|
|
SymmetricSuite::new(Kdf::HkdfSha256, Aead::ChaCha20Poly1305),
|
|
];
|
|
let key_config = KeyConfig::new(key_id, kem, symmetric).map_err(|_| NS_ERROR_FAILURE)?;
|
|
let server = Server::new(key_config).map_err(|_| NS_ERROR_FAILURE)?;
|
|
let oblivious_http_server = ObliviousHttpServer::allocate(InitObliviousHttpServer {
|
|
server: RefCell::new(server),
|
|
});
|
|
oblivious_http_server
|
|
.query_interface::<nsIObliviousHttpServer>()
|
|
.ok_or(NS_ERROR_FAILURE)
|
|
}
|
|
|
|
xpcom_method!(decode_config_list => DecodeConfigList(encoded_config_list: *const ThinVec<u8>) -> ThinVec<ThinVec<u8>>);
|
|
fn decode_config_list(
|
|
&self,
|
|
encoded_config_list: &ThinVec<u8>,
|
|
) -> Result<ThinVec<ThinVec<u8>>, nsresult> {
|
|
let configs = KeyConfig::decode_list(encoded_config_list)
|
|
.map_err(|_| NS_ERROR_FAILURE)?
|
|
.into_iter()
|
|
.map(|config| config.encode().unwrap())
|
|
.map(ThinVec::from)
|
|
.collect();
|
|
Ok(configs)
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn oblivious_http_constructor(
|
|
iid: *const xpcom::nsIID,
|
|
result: *mut *mut xpcom::reexports::libc::c_void,
|
|
) -> nserror::nsresult {
|
|
let oblivious_http = ObliviousHttp::allocate(InitObliviousHttp {});
|
|
unsafe { oblivious_http.QueryInterface(iid, result) }
|
|
}
|