mirror of
https://github.com/signalapp/libsignal.git
synced 2024-09-20 03:52:17 +02:00
JNI for HSM enclave client.
This commit is contained in:
parent
a7bf226166
commit
9caa6615b9
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -809,6 +809,7 @@ dependencies = [
|
||||
"async-trait",
|
||||
"device-transfer",
|
||||
"futures-util",
|
||||
"hsm-enclave",
|
||||
"jni",
|
||||
"libc",
|
||||
"libsignal-bridge-macros",
|
||||
|
@ -136,6 +136,13 @@ public final class Native {
|
||||
|
||||
public static native byte[] HKDF_DeriveSecrets(int outputLength, int version, byte[] ikm, byte[] label, byte[] salt);
|
||||
|
||||
public static native void HsmEnclaveClient_CompleteHandshake(long cli, byte[] handshakeReceived);
|
||||
public static native void HsmEnclaveClient_Destroy(long handle);
|
||||
public static native byte[] HsmEnclaveClient_EstablishedRecv(long cli, byte[] receivedCiphertext);
|
||||
public static native byte[] HsmEnclaveClient_EstablishedSend(long cli, byte[] plaintextToSend);
|
||||
public static native byte[] HsmEnclaveClient_InitialRequest(long cli);
|
||||
public static native long HsmEnclaveClient_New(byte[] trustedPublicKey, byte[] trustedCodeHashes);
|
||||
|
||||
public static native long[] IdentityKeyPair_Deserialize(byte[] data);
|
||||
public static native byte[] IdentityKeyPair_Serialize(long publicKey, long privateKey);
|
||||
|
||||
|
@ -0,0 +1,6 @@
|
||||
package org.signal.libsignal.hsmenclave;
|
||||
|
||||
public class EnclaveCommunicationFailureException extends Exception {
|
||||
public EnclaveCommunicationFailureException(String msg) { super(msg); }
|
||||
public EnclaveCommunicationFailureException(Throwable t) { super(t); }
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
//
|
||||
// Copyright 2021 Signal Messenger, LLC.
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
//
|
||||
|
||||
package org.signal.libsignal.hsmenclave;
|
||||
|
||||
import org.signal.client.internal.Native;
|
||||
import org.whispersystems.libsignal.InvalidKeyException;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* HsmEnclaveClient provides bindings to interact with Signal's HSM-backed enclave.
|
||||
*
|
||||
* Interaction with the enclave is done over a websocket, which is handled by the client. Once the websocket
|
||||
* has been initiated, the client establishes a connection in the following manner:
|
||||
*
|
||||
* <ul>
|
||||
* <li>send HsmEnclaveClient.initialRequest()</li>
|
||||
* <li>receive a response and pass to HsmEnclaveClient.completeHandshake()</li>
|
||||
* </ul>
|
||||
*
|
||||
* After a connection has been established, a client may send or receive messages. To send a message, they
|
||||
* formulate the plaintext, then pass it to HsmEnclaveClient.establishedSend() to get the ciphertext message
|
||||
* to pass along. When a message is received (as ciphertext), it is passed to HsmEnclaveClient.establishedRecv(),
|
||||
* which decrypts and verifies it, passing the plaintext back to the client for processing.
|
||||
*/
|
||||
public class HsmEnclaveClient {
|
||||
private long handle;
|
||||
|
||||
public HsmEnclaveClient(byte[] public_key, List<byte[]> code_hashes) {
|
||||
ByteArrayOutputStream concatHashes = new ByteArrayOutputStream();
|
||||
for (byte[] hash : code_hashes) {
|
||||
if (hash.length != 32) {
|
||||
throw new IllegalArgumentException("code hash length must be 32");
|
||||
}
|
||||
try {
|
||||
concatHashes.write(hash);
|
||||
} catch (IOException e) {
|
||||
throw new AssertionError("writing to ByteArrayOutputStream failed", e);
|
||||
}
|
||||
}
|
||||
this.handle = Native.HsmEnclaveClient_New(public_key, concatHashes.toByteArray());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() {
|
||||
Native.HsmEnclaveClient_Destroy(this.handle);
|
||||
}
|
||||
|
||||
/** Initial request to send to HSM enclave, to begin handshake. */
|
||||
public byte[] initialRequest() {
|
||||
return Native.HsmEnclaveClient_InitialRequest(this.handle);
|
||||
}
|
||||
|
||||
/** Called by client upon receipt of first message from HSM enclave, to complete handshake. */
|
||||
public void completeHandshake(byte[] handshakeResponse) {
|
||||
Native.HsmEnclaveClient_CompleteHandshake(this.handle, handshakeResponse);
|
||||
}
|
||||
|
||||
/** Called by client after completeHandshake has succeeded, to encrypt a message to send. */
|
||||
public byte[] establishedSend(byte[] plaintextToSend) {
|
||||
return Native.HsmEnclaveClient_EstablishedSend(this.handle, plaintextToSend);
|
||||
}
|
||||
|
||||
/** Called by client after completeHandshake has succeeded, to decrypt a received message. */
|
||||
public byte[] establishedRecv(byte[] receivedCiphertext) {
|
||||
return Native.HsmEnclaveClient_EstablishedRecv(this.handle, receivedCiphertext);
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
package org.signal.libsignal.hsmenclave;
|
||||
|
||||
public class TrustedCodeMismatchException extends Exception {
|
||||
public TrustedCodeMismatchException(String msg) { super(msg); }
|
||||
public TrustedCodeMismatchException(Throwable t) { super(t); }
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
//
|
||||
// Copyright 2021 Signal Messenger, LLC.
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
//
|
||||
|
||||
package org.signal.libsignal.hsmenclave;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class HsmEnclaveClientTest extends TestCase {
|
||||
public void testCreateClient() throws Exception {
|
||||
byte[] validKey = new byte[32];
|
||||
List<byte[]> hashes = new ArrayList<>();
|
||||
hashes.add(new byte[]{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0});
|
||||
hashes.add(new byte[]{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1});
|
||||
HsmEnclaveClient hsmEnclaveClient = new HsmEnclaveClient(validKey, hashes);
|
||||
byte[] initialMessage = hsmEnclaveClient.initialRequest();
|
||||
assertEquals(112, initialMessage.length);
|
||||
}
|
||||
|
||||
public void testCreateClientFailsWithInvalidPublicKey() {
|
||||
byte[] invalidKey = new byte[31];
|
||||
List<byte[]> hashes = new ArrayList<>();
|
||||
hashes.add(new byte[]{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0});
|
||||
hashes.add(new byte[]{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1});
|
||||
try {
|
||||
new HsmEnclaveClient(invalidKey, hashes);
|
||||
} catch (IllegalArgumentException e) {
|
||||
return;
|
||||
}
|
||||
fail();
|
||||
}
|
||||
|
||||
public void testCreateClientFailsWithInvalidHash() {
|
||||
byte[] validKey = new byte[32];
|
||||
List<byte[]> hashes = new ArrayList<>();
|
||||
hashes.add(new byte[]{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0});
|
||||
hashes.add(new byte[]{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0});
|
||||
try {
|
||||
new HsmEnclaveClient(validKey, hashes);
|
||||
} catch (IllegalArgumentException e) {
|
||||
return;
|
||||
}
|
||||
fail();
|
||||
}
|
||||
|
||||
public void testCreateClientFailsWithNoHashes() {
|
||||
byte[] validKey = new byte[32];
|
||||
List<byte[]> hashes = new ArrayList<>();
|
||||
try {
|
||||
new HsmEnclaveClient(validKey, hashes);
|
||||
} catch (IllegalArgumentException e) {
|
||||
return;
|
||||
}
|
||||
fail();
|
||||
}
|
||||
|
||||
public void testEstablishedSendFailsPriorToEstablishment() {
|
||||
byte[] validKey = new byte[32];
|
||||
List<byte[]> hashes = new ArrayList<>();
|
||||
hashes.add(new byte[]{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0});
|
||||
HsmEnclaveClient hsmEnclaveClient = new HsmEnclaveClient(validKey, hashes);
|
||||
try {
|
||||
hsmEnclaveClient.establishedSend(new byte[]{1, 2, 3});
|
||||
} catch (IllegalStateException e) {
|
||||
return;
|
||||
}
|
||||
fail();
|
||||
}
|
||||
|
||||
public void testEstablishedRecvFailsPriorToEstablishment() {
|
||||
byte[] validKey = new byte[32];
|
||||
List<byte[]> hashes = new ArrayList<>();
|
||||
hashes.add(new byte[]{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0});
|
||||
HsmEnclaveClient hsmEnclaveClient = new HsmEnclaveClient(validKey, hashes);
|
||||
try {
|
||||
hsmEnclaveClient.establishedRecv(new byte[]{1, 2, 3});
|
||||
} catch (IllegalStateException e) {
|
||||
return;
|
||||
}
|
||||
fail();
|
||||
}
|
||||
}
|
@ -14,6 +14,7 @@ license = "AGPL-3.0-only"
|
||||
libsignal-protocol = { path = "../../protocol" }
|
||||
signal-crypto = { path = "../../crypto" }
|
||||
device-transfer = { path = "../../device-transfer" }
|
||||
hsm-enclave = { path = "../../hsm-enclave" }
|
||||
libsignal-bridge-macros = { path = "macros" }
|
||||
aes-gcm-siv = "0.10.1"
|
||||
futures-util = "0.3.7"
|
||||
|
113
rust/bridge/shared/src/hsm_enclave.rs
Normal file
113
rust/bridge/shared/src/hsm_enclave.rs
Normal file
@ -0,0 +1,113 @@
|
||||
//
|
||||
// Copyright 2021 Signal Messenger, LLC.
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
//
|
||||
|
||||
use ::hsm_enclave;
|
||||
use libsignal_bridge_macros::*;
|
||||
|
||||
use crate::support::*;
|
||||
use crate::*;
|
||||
use hsm_enclave::Result;
|
||||
|
||||
pub enum HsmEnclaveClient {
|
||||
ConnectionEstablishment(hsm_enclave::ClientConnectionEstablishment),
|
||||
Connection(hsm_enclave::ClientConnection),
|
||||
InvalidConnectionState,
|
||||
}
|
||||
|
||||
impl HsmEnclaveClient {
|
||||
pub fn new(trusted_public_key: &[u8], trusted_code_hashes: &[u8]) -> Result<Self> {
|
||||
if trusted_public_key.len() != hsm_enclave::PUB_KEY_SIZE {
|
||||
return Err(hsm_enclave::Error::InvalidPublicKeyError);
|
||||
}
|
||||
if trusted_code_hashes.is_empty()
|
||||
|| trusted_code_hashes.len() % hsm_enclave::CODE_HASH_SIZE != 0
|
||||
{
|
||||
return Err(hsm_enclave::Error::InvalidCodeHashError);
|
||||
}
|
||||
let mut pubkey = [0u8; hsm_enclave::PUB_KEY_SIZE];
|
||||
pubkey.copy_from_slice(trusted_public_key);
|
||||
let mut hashes: Vec<[u8; hsm_enclave::CODE_HASH_SIZE]> = Vec::new();
|
||||
for code_hash in trusted_code_hashes.chunks(hsm_enclave::CODE_HASH_SIZE) {
|
||||
let mut hash = [0u8; hsm_enclave::CODE_HASH_SIZE];
|
||||
hash.copy_from_slice(code_hash);
|
||||
hashes.push(hash);
|
||||
}
|
||||
Ok(HsmEnclaveClient::ConnectionEstablishment(
|
||||
hsm_enclave::ClientConnectionEstablishment::new(pubkey, hashes)?,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn initial_request(&self) -> Result<&[u8]> {
|
||||
match self {
|
||||
HsmEnclaveClient::ConnectionEstablishment(c) => Ok(c.initial_request()),
|
||||
_ => Err(hsm_enclave::Error::InvalidBridgeStateError),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn complete_handshake(&mut self, handshake_received: &[u8]) -> Result<()> {
|
||||
match std::mem::replace(self, HsmEnclaveClient::InvalidConnectionState) {
|
||||
HsmEnclaveClient::ConnectionEstablishment(c) => {
|
||||
*self = HsmEnclaveClient::Connection(c.complete(handshake_received)?);
|
||||
Ok(())
|
||||
}
|
||||
_ => Err(hsm_enclave::Error::InvalidBridgeStateError),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn established_send(&mut self, plaintext_to_send: &[u8]) -> Result<Vec<u8>> {
|
||||
match self {
|
||||
HsmEnclaveClient::Connection(c) => c.send(plaintext_to_send),
|
||||
_ => Err(hsm_enclave::Error::InvalidBridgeStateError),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn established_recv(&mut self, received_ciphertext: &[u8]) -> Result<Vec<u8>> {
|
||||
match self {
|
||||
HsmEnclaveClient::Connection(c) => c.recv(received_ciphertext),
|
||||
_ => Err(hsm_enclave::Error::InvalidBridgeStateError),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bridge_handle!(HsmEnclaveClient, mut = true, ffi = false, node = false);
|
||||
|
||||
#[bridge_fn(node = false, ffi = false)]
|
||||
fn HsmEnclaveClient_New(
|
||||
trusted_public_key: &[u8],
|
||||
trusted_code_hashes: &[u8],
|
||||
) -> Result<HsmEnclaveClient> {
|
||||
HsmEnclaveClient::new(trusted_public_key, trusted_code_hashes)
|
||||
}
|
||||
|
||||
#[bridge_fn_buffer(node = false, ffi = false)]
|
||||
fn HsmEnclaveClient_InitialRequest<T: Env>(env: T, cli: &HsmEnclaveClient) -> Result<T::Buffer> {
|
||||
Ok(env.buffer(cli.initial_request()?))
|
||||
}
|
||||
|
||||
#[bridge_fn_void(node = false, ffi = false)]
|
||||
fn HsmEnclaveClient_CompleteHandshake(
|
||||
cli: &mut HsmEnclaveClient,
|
||||
handshake_received: &[u8],
|
||||
) -> Result<()> {
|
||||
cli.complete_handshake(handshake_received)
|
||||
}
|
||||
|
||||
#[bridge_fn_buffer(node = false, ffi = false)]
|
||||
fn HsmEnclaveClient_EstablishedSend<T: Env>(
|
||||
env: T,
|
||||
cli: &mut HsmEnclaveClient,
|
||||
plaintext_to_send: &[u8],
|
||||
) -> Result<T::Buffer> {
|
||||
Ok(env.buffer(cli.established_send(plaintext_to_send)?))
|
||||
}
|
||||
|
||||
#[bridge_fn_buffer(node = false, ffi = false)]
|
||||
fn HsmEnclaveClient_EstablishedRecv<T: Env>(
|
||||
env: T,
|
||||
cli: &mut HsmEnclaveClient,
|
||||
received_ciphertext: &[u8],
|
||||
) -> Result<T::Buffer> {
|
||||
Ok(env.buffer(cli.established_recv(received_ciphertext)?))
|
||||
}
|
@ -567,6 +567,16 @@ impl<T: ResultTypeInfo> ResultTypeInfo for Result<T, device_transfer::Error> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ResultTypeInfo> ResultTypeInfo for Result<T, hsm_enclave::Error> {
|
||||
type ResultType = T::ResultType;
|
||||
fn convert_into(self, env: &JNIEnv) -> SignalJniResult<Self::ResultType> {
|
||||
T::convert_into(self?, env)
|
||||
}
|
||||
fn convert_into_jobject(signal_jni_result: &SignalJniResult<Self::ResultType>) -> JObject {
|
||||
<T as ResultTypeInfo>::convert_into_jobject(signal_jni_result)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ResultTypeInfo> ResultTypeInfo for Result<T, signal_crypto::Error> {
|
||||
type ResultType = T::ResultType;
|
||||
fn convert_into(self, env: &JNIEnv) -> SignalJniResult<Self::ResultType> {
|
||||
|
@ -8,6 +8,7 @@ use jni::{JNIEnv, JavaVM};
|
||||
use std::fmt;
|
||||
|
||||
use device_transfer::Error as DeviceTransferError;
|
||||
use hsm_enclave::Error as HsmEnclaveError;
|
||||
use libsignal_protocol::*;
|
||||
use signal_crypto::Error as SignalCryptoError;
|
||||
|
||||
@ -24,6 +25,7 @@ pub enum SignalJniError {
|
||||
UnexpectedJniResultType(&'static str, &'static str),
|
||||
NullHandle,
|
||||
IntegerOverflow(String),
|
||||
HsmEnclave(HsmEnclaveError),
|
||||
UnexpectedPanic(std::boxed::Box<dyn std::any::Any + std::marker::Send>),
|
||||
}
|
||||
|
||||
@ -42,6 +44,9 @@ impl fmt::Display for SignalJniError {
|
||||
SignalJniError::IntegerOverflow(m) => {
|
||||
write!(f, "integer overflow during conversion of {}", m)
|
||||
}
|
||||
SignalJniError::HsmEnclave(e) => {
|
||||
write!(f, "{}", e)
|
||||
}
|
||||
SignalJniError::UnexpectedPanic(e) => match e.downcast_ref::<&'static str>() {
|
||||
Some(s) => write!(f, "unexpected panic: {}", s),
|
||||
None => write!(f, "unknown unexpected panic"),
|
||||
@ -62,6 +67,12 @@ impl From<DeviceTransferError> for SignalJniError {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<HsmEnclaveError> for SignalJniError {
|
||||
fn from(e: HsmEnclaveError) -> SignalJniError {
|
||||
SignalJniError::HsmEnclave(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SignalCryptoError> for SignalJniError {
|
||||
fn from(e: SignalCryptoError) -> SignalJniError {
|
||||
SignalJniError::SignalCrypto(e)
|
||||
|
@ -9,6 +9,7 @@ use jni::objects::{JThrowable, JValue};
|
||||
use jni::sys::jobject;
|
||||
|
||||
use device_transfer::Error as DeviceTransferError;
|
||||
use hsm_enclave::Error as HsmEnclaveError;
|
||||
use libsignal_protocol::*;
|
||||
use signal_crypto::Error as SignalCryptoError;
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
@ -293,6 +294,20 @@ fn throw_error(env: &JNIEnv, error: SignalJniError) {
|
||||
| SignalJniError::UnexpectedJniResultType(_, _) => {
|
||||
unreachable!("already handled in prior match")
|
||||
}
|
||||
|
||||
SignalJniError::HsmEnclave(HsmEnclaveError::HSMCommunicationError(_)) => {
|
||||
"org/signal/libsignal/hsmenclave/EnclaveCommunicationFailureException"
|
||||
}
|
||||
SignalJniError::HsmEnclave(HsmEnclaveError::TrustedCodeError) => {
|
||||
"org/signal/libsignal/hsmenclave/TrustedCodeMismatchException"
|
||||
}
|
||||
SignalJniError::HsmEnclave(HsmEnclaveError::InvalidPublicKeyError)
|
||||
| SignalJniError::HsmEnclave(HsmEnclaveError::InvalidCodeHashError) => {
|
||||
"java/lang/IllegalArgumentException"
|
||||
}
|
||||
SignalJniError::HsmEnclave(HsmEnclaveError::InvalidBridgeStateError) => {
|
||||
"java/lang/IllegalStateException"
|
||||
}
|
||||
};
|
||||
|
||||
if let Err(e) = env.throw_new(exception_type, error.to_string()) {
|
||||
|
@ -30,3 +30,6 @@ pub mod protocol;
|
||||
// Desktop does not make use of device transfer certificates
|
||||
#[cfg(any(feature = "jni", feature = "ffi"))]
|
||||
pub mod device_transfer;
|
||||
|
||||
#[cfg(any(feature = "jni"))]
|
||||
pub mod hsm_enclave;
|
||||
|
@ -13,15 +13,24 @@ use std::fmt;
|
||||
|
||||
mod snow_resolver;
|
||||
|
||||
/// Error types for device transfer.
|
||||
/// Error types for HSM enclave.
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
/// Failure to connect to a trusted HSM.
|
||||
HSMCommunicationError(snow::Error),
|
||||
/// Failure to connect to trusted code on the given HSM.
|
||||
TrustedCodeError,
|
||||
/// Invalid public key provided (used in bridging)
|
||||
InvalidPublicKeyError,
|
||||
/// Invalid code hash provided (used in bridging)
|
||||
InvalidCodeHashError,
|
||||
/// Invalid state of wrapper (used in bridging)
|
||||
InvalidBridgeStateError,
|
||||
}
|
||||
|
||||
/// Result type for HSM enclave.
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
@ -29,6 +38,19 @@ impl fmt::Display for Error {
|
||||
Error::TrustedCodeError => {
|
||||
write!(f, "Trusted HSM process does not match trusted code hash")
|
||||
}
|
||||
Error::InvalidPublicKeyError => {
|
||||
write!(f, "Invalid public key, must be {} bytes", PUB_KEY_SIZE)
|
||||
}
|
||||
Error::InvalidCodeHashError => {
|
||||
write!(
|
||||
f,
|
||||
"Invalid code hashes, must be >0 hashes, each exactly {} bytes",
|
||||
CODE_HASH_SIZE
|
||||
)
|
||||
}
|
||||
Error::InvalidBridgeStateError => {
|
||||
write!(f, "Invalid bridge state")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -67,7 +89,7 @@ impl ClientConnectionEstablishment {
|
||||
pub fn new(
|
||||
trusted_public_key: [u8; PUB_KEY_SIZE],
|
||||
trusted_code_hashes: Vec<[u8; CODE_HASH_SIZE]>,
|
||||
) -> Result<Self, Error> {
|
||||
) -> Result<Self> {
|
||||
let mut hs = snow::Builder::with_resolver(
|
||||
NOISE_PATTERN.parse().expect("valid"),
|
||||
Box::new(snow_resolver::Resolver),
|
||||
@ -91,7 +113,7 @@ impl ClientConnectionEstablishment {
|
||||
}
|
||||
|
||||
/// Completes client connection initiation, returns a valid client connection.
|
||||
pub fn complete(mut self, initial_received: &[u8]) -> Result<ClientConnection, Error> {
|
||||
pub fn complete(mut self, initial_received: &[u8]) -> Result<ClientConnection> {
|
||||
let mut received_hash = [0u8; CODE_HASH_SIZE];
|
||||
let size = self.hs.read_message(initial_received, &mut received_hash)?;
|
||||
if size != received_hash.len() {
|
||||
@ -130,7 +152,7 @@ const NOISE_TRANSPORT_PER_PAYLOAD_MAX: usize =
|
||||
|
||||
impl ClientConnection {
|
||||
/// Wrap a plaintext message to be sent, returning the ciphertext.
|
||||
pub fn send(&mut self, plaintext_to_send: &[u8]) -> Result<Vec<u8>, Error> {
|
||||
pub fn send(&mut self, plaintext_to_send: &[u8]) -> Result<Vec<u8>> {
|
||||
let max_ciphertext_size = plaintext_to_send.len()
|
||||
+ (1 + plaintext_to_send.len() / NOISE_TRANSPORT_PER_PAYLOAD_MAX)
|
||||
* NOISE_HANDSHAKE_OVERHEAD;
|
||||
@ -146,7 +168,7 @@ impl ClientConnection {
|
||||
}
|
||||
|
||||
/// Unwrap a ciphertext message that's been received, returning the plaintext.
|
||||
pub fn recv(&mut self, received_ciphertext: &[u8]) -> Result<Vec<u8>, Error> {
|
||||
pub fn recv(&mut self, received_ciphertext: &[u8]) -> Result<Vec<u8>> {
|
||||
let mut received_plaintext: Vec<u8> = vec![0u8; received_ciphertext.len()];
|
||||
let mut total_size = 0;
|
||||
for chunk in received_ciphertext.chunks(NOISE_TRANSPORT_PER_PACKET_MAX) {
|
||||
|
@ -7,7 +7,7 @@ use hsm_enclave::*;
|
||||
const NOISE_PATTERN: &str = "Noise_NK_25519_AESGCM_SHA256";
|
||||
|
||||
#[test]
|
||||
fn test_hsm_enclave_happy_path() -> Result<(), Error> {
|
||||
fn test_hsm_enclave_happy_path() -> Result<()> {
|
||||
// Spin up a handshake for the server-side.
|
||||
let keypair = snow::Builder::new(NOISE_PATTERN.parse()?).generate_keypair()?;
|
||||
let mut server_hs = snow::Builder::new(NOISE_PATTERN.parse()?)
|
||||
@ -53,7 +53,7 @@ fn test_hsm_enclave_happy_path() -> Result<(), Error> {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hsm_enclave_codehash_mismatch() -> Result<(), Error> {
|
||||
fn test_hsm_enclave_codehash_mismatch() -> Result<()> {
|
||||
// Spin up a handshake for the server-side.
|
||||
let keypair = snow::Builder::new(NOISE_PATTERN.parse()?).generate_keypair()?;
|
||||
let mut server_hs = snow::Builder::new(NOISE_PATTERN.parse()?)
|
||||
|
Loading…
Reference in New Issue
Block a user