Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions parsec-openssl-provider-shared/e2e_tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ foreign-types-shared = "0.1.1"
parsec-openssl-provider = { path ="../../parsec-openssl-provider" }
parsec-client = "0.16.0"
sha2 = "0.10.8"
openssl = "0.10.63"

[build-dependencies]
pkg-config = "0.3.18"
Expand Down
120 changes: 120 additions & 0 deletions parsec-openssl-provider-shared/e2e_tests/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,14 @@

// Needed to access as_ptr function for LibCtx
pub use foreign_types_shared::ForeignType;
pub use openssl::ssl::{Ssl, SslContext, SslContextBuilder, SslFiletype, SslMethod, SslVerifyMode};
pub use parsec_openssl_provider::parsec_openssl2::openssl::{lib_ctx::LibCtx, provider::Provider};
pub use parsec_openssl_provider::parsec_openssl2::openssl_bindings::*;
use parsec_openssl_provider::parsec_openssl2::openssl_returns_1;
use parsec_openssl_provider::PARSEC_PROVIDER_DFLT_PROPERTIES;
pub use std::io::{Read, Write};
pub use std::net::{SocketAddr, TcpListener, TcpStream};
pub use std::thread::{self, JoinHandle};

// Loads a provider into the given library context
pub fn load_provider(lib_ctx: &LibCtx, provider_name: &str, provider_path: String) -> Provider {
Expand Down Expand Up @@ -41,3 +45,119 @@ pub unsafe fn load_key(

EVP_PKEY_CTX_free(evp_ctx);
}

// Server object with configuration needed for TLS handshake
pub struct Server {
ssl_method: SslMethod,
certificate: Option<String>,
private_key: Option<String>,
ca_certificate: Option<String>,
ssl_mode: SslVerifyMode,
}

impl Server {
pub fn new(
cert: Option<String>,
key: Option<String>,
ca: Option<String>,
mode: SslVerifyMode,
) -> Server {
Server {
ssl_method: SslMethod::tls_server(),
certificate: cert,
private_key: key,
ca_certificate: ca,
ssl_mode: mode,
}
}

// Uses all the Server configurations to build a SslContext object
pub fn build(&mut self) -> SslContext {
let mut ctx_builder = SslContext::builder(self.ssl_method).unwrap();
if let Some(certificate) = &self.certificate {
ctx_builder
.set_certificate_file(certificate, SslFiletype::PEM)
.unwrap();
}
if let Some(key) = &self.private_key {
ctx_builder
.set_private_key_file(key, SslFiletype::PEM)
.unwrap();
}
if let Some(ca_cert) = &self.ca_certificate {
ctx_builder.set_ca_file(ca_cert).unwrap();
}
ctx_builder.set_verify(self.ssl_mode);
ctx_builder.build()
}

// Opens a TCP stream listener and accepts any incoming SSL requests
// coming from client. The server waits in a separate thread and returns
// the handle to the caller.
pub fn accept(mut self, listener: TcpListener) {
let _handle = thread::spawn(move || {
let server_context = self.build();
let stream = listener.accept().unwrap().0;
let ssl = Ssl::new(&server_context).unwrap();
let handshake_result = ssl.accept(stream);
let mut stream = handshake_result.unwrap();
stream.write_all(&[0]).unwrap();
});
}
}

// Client object with configuration needed for TLS handshake
pub struct Client {
ssl_method: SslMethod,
certificate: Option<String>,
private_key: Option<String>,
ca_certificate: Option<String>,
ssl_mode: SslVerifyMode,
}

impl Client {
pub fn new(
cert: Option<String>,
key: Option<String>,
ca: Option<String>,
mode: SslVerifyMode,
) -> Client {
Client {
ssl_method: SslMethod::tls_client(),
certificate: cert,
private_key: key,
ca_certificate: ca,
ssl_mode: mode,
}
}

// ToDo: This needs to modified in the future to use the PKey object from parsec provider
// Uses all the Client configurations to build a SslContext object
pub fn build(&mut self) -> SslContext {
let mut ctx_builder = SslContext::builder(self.ssl_method).unwrap();
if let Some(certificate) = &self.certificate {
ctx_builder
.set_certificate_file(certificate, SslFiletype::PEM)
.unwrap();
}
if let Some(key) = &self.private_key {
ctx_builder
.set_private_key_file(key, SslFiletype::PEM)
.unwrap();
}
if let Some(ca_cert) = &self.ca_certificate {
ctx_builder.set_ca_file(ca_cert).unwrap();
}
ctx_builder.set_verify(self.ssl_mode);
ctx_builder.build()
}

// Creates a TCP stream and initiates a TLS handshake to the server
pub fn connect(mut self, addr: SocketAddr) {
let socket = TcpStream::connect(addr).unwrap();
let client_ctx = self.build();
let ssl = Ssl::new(&client_ctx).unwrap();
let mut channel = ssl.connect(socket).unwrap();
channel.read_exact(&mut [0]).unwrap();
}
}
153 changes: 153 additions & 0 deletions parsec-openssl-provider-shared/e2e_tests/tests/handshake.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
// Copyright 2024 Contributors to the Parsec project.
// SPDX-License-Identifier: Apache-2.0
use e2e_tests::*;

#[test]
fn test_handshake_no_authentication() {
let listener = TcpListener::bind("127.0.0.1:0").unwrap();
let addr = listener.local_addr().unwrap();

let server = Server::new(
Some(String::from("../../tests/tls/server/server_cert.pem")),
Some(String::from("../../tests/tls/server/server_priv_key.pem")),
Some(String::from("../../tests/tls/ca/ca_cert.pem")),
SslVerifyMode::NONE,
);
server.accept(listener);

let client = Client::new(None, None, None, SslVerifyMode::NONE);
client.connect(addr);
}

#[should_panic]
#[test]
fn test_handshake_server_authentication_no_client_ca() {
let listener = TcpListener::bind("127.0.0.1:0").unwrap();
let addr = listener.local_addr().unwrap();

let server = Server::new(
Some(String::from("../../tests/tls/server/server_cert.pem")),
Some(String::from("../../tests/tls/server/server_priv_key.pem")),
Some(String::from("../../tests/tls/ca/ca_cert.pem")),
SslVerifyMode::NONE,
);
server.accept(listener);

let client = Client::new(None, None, None, SslVerifyMode::PEER);
client.connect(addr);
}

#[test]
fn test_handshake_server_authentication_with_client_ca() {
let listener = TcpListener::bind("127.0.0.1:0").unwrap();
let addr = listener.local_addr().unwrap();

let server = Server::new(
Some(String::from("../../tests/tls/server/server_cert.pem")),
Some(String::from("../../tests/tls/server/server_priv_key.pem")),
Some(String::from("../../tests/tls/ca/ca_cert.pem")),
SslVerifyMode::NONE,
);
server.accept(listener);

let client = Client::new(
None,
None,
Some(String::from("../../tests/tls/ca/ca_cert.pem")),
SslVerifyMode::PEER,
);
client.connect(addr);
}

#[should_panic]
#[test]
fn test_handshake_client_authentication_with_no_client_settings() {
let listener = TcpListener::bind("127.0.0.1:0").unwrap();
let addr = listener.local_addr().unwrap();

let server = Server::new(
Some(String::from("../../tests/tls/server/server_cert.pem")),
Some(String::from("../../tests/tls/server/server_priv_key.pem")),
Some(String::from("../../tests/tls/ca/ca_cert.pem")),
SslVerifyMode::PEER | SslVerifyMode::FAIL_IF_NO_PEER_CERT,
);
server.accept(listener);

let client = Client::new(
None,
None,
Some(String::from("../../tests/tls/ca/ca_cert.pem")),
SslVerifyMode::PEER,
);
client.connect(addr);
}

#[should_panic]
#[test]
fn test_handshake_client_authentication_with_no_client_key() {
let listener = TcpListener::bind("127.0.0.1:0").unwrap();
let addr = listener.local_addr().unwrap();

let server = Server::new(
Some(String::from("../../tests/tls/server/server_cert.pem")),
Some(String::from("../../tests/tls/server/server_priv_key.pem")),
Some(String::from("../../tests/tls/ca/ca_cert.pem")),
SslVerifyMode::PEER | SslVerifyMode::FAIL_IF_NO_PEER_CERT,
);
server.accept(listener);

let client = Client::new(
Some(String::from("../../tests/tls/client/client_cert.pem")),
None,
Some(String::from("../../tests/tls/ca/ca_cert.pem")),
SslVerifyMode::PEER,
);
client.connect(addr);
}

#[test]
fn test_handshake_client_authentication() {
let socket = TcpListener::bind("127.0.0.1:0").unwrap();
let addr = socket.local_addr().unwrap();

let server = Server::new(
Some(String::from("../../tests/tls/server/server_cert.pem")),
Some(String::from("../../tests/tls/server/server_priv_key.pem")),
Some(String::from("../../tests/tls/ca/ca_cert.pem")),
SslVerifyMode::FAIL_IF_NO_PEER_CERT | SslVerifyMode::PEER,
);
server.accept(socket);

let client = Client::new(
Some(String::from("../../tests/tls/client/client_cert.pem")),
Some(String::from("../../tests/tls/client/client_priv_key.pem")),
Some(String::from("../../tests/tls/ca/ca_cert.pem")),
SslVerifyMode::PEER,
);
client.connect(addr);
}

#[should_panic]
#[test]
fn test_handshake_client_authentication_with_fake_ca() {
let socket = TcpListener::bind("127.0.0.1:0").unwrap();
let addr = socket.local_addr().unwrap();

let server = Server::new(
Some(String::from("../../tests/tls/server/server_cert.pem")),
Some(String::from("../../tests/tls/server/server_priv_key.pem")),
Some(String::from("../../tests/tls/ca/ca_cert.pem")),
SslVerifyMode::FAIL_IF_NO_PEER_CERT | SslVerifyMode::PEER,
);
server.accept(socket);

let client = Client::new(
Some(String::from("../../tests/tls/fake_client/client_cert.pem")),
Some(String::from(
"../../tests/tls/fake_client/client_priv_key.pem",
)),
Some(String::from("../../tests/tls/fake_ca/ca_cert.pem")),
SslVerifyMode::PEER,
);
client.connect(addr);
}
1 change: 1 addition & 0 deletions parsec-openssl-provider-shared/e2e_tests/tests/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright 2024 Contributors to the Parsec project.
// SPDX-License-Identifier: Apache-2.0

mod handshake;
mod keys;
mod provider;
mod sign;
22 changes: 11 additions & 11 deletions tests/setup_tls.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,17 @@
generate_ca_certs() {
CA_DIRECTORY=$1
CA_CERTIFICATE=${CA_DIRECTORY}/ca_cert.pem
CA_PRIV_KEY=${CA_DIRECTORY}/ca_private_key.pem
CA_PRIV_KEY=${CA_DIRECTORY}/ca_priv_key.pem

# Generate a self signed certificate for the CA along with a key.
if [ ! -f "${CA_CERTIFICATE}" ]; then
mkdir -p "${CA_DIRECTORY}"
chmod 700 "${CA_DIRECTORY}"

openssl req -x509 -nodes -newkey rsa:2048 \
openssl req -x509 -nodes -days 1000 -newkey rsa:2048 \
-keyout "${CA_PRIV_KEY}" \
-out "${CA_CERTIFICATE}" \
-subj "/C=UK/ST=Parsec /L=Parsec/O=Parsec/CN=parsec.com" > /dev/null 2>&1
-subj "/C=UK/ST=Parsec /L=Parsec/O=Parsec/CN=parsec_ca.com" > /dev/null 2>&1

if [ $? -ne 0 ]; then
echo "FAILED"
Expand All @@ -43,11 +43,11 @@ generate_server_certs() {
SERVER_DIRECTORY=$1
SERVER_CERTIFICATE=${SERVER_DIRECTORY}/server_cert.pem
SERVER_CSR=${SERVER_DIRECTORY}/server_cert.csr
SERVER_PRIV_KEY=${SERVER_DIRECTORY}/server_private_key.pem
SERVER_PRIV_KEY=${SERVER_DIRECTORY}/server_priv_key.pem

CA_DIRECTORY=$2
CA_CERTIFICATE=${CA_DIRECTORY}/ca_cert.pem
CA_PRIV_KEY=${CA_DIRECTORY}/ca_private_key.pem
CA_PRIV_KEY=${CA_DIRECTORY}/ca_priv_key.pem

if [ ! -f "${SERVER_CSR}" ]; then
mkdir -p "${SERVER_DIRECTORY}" > /dev/null 2>&1
Expand All @@ -64,14 +64,14 @@ generate_server_certs() {
openssl req -new \
-key "${SERVER_PRIV_KEY}" \
-out "${SERVER_CSR}" \
-subj "/C=UK/ST=Parsec /L=Parsec/O=Parsec/CN=parsec.com" > /dev/null 2>&1
-subj "/C=UK/ST=Parsec /L=Parsec/O=Parsec/CN=parsec_server.com" > /dev/null 2>&1
if [ $? -ne 0 ]; then
echo "FAILED TO GENERATE CERTIFICATE REQUEST"
exit 1
fi

# Generate certificate
openssl x509 -req -in "${SERVER_CSR}" \
openssl x509 -req -days 1000 -in "${SERVER_CSR}" \
-CA "${CA_CERTIFICATE}" -CAkey "${CA_PRIV_KEY}" \
-CAcreateserial -out "${SERVER_CERTIFICATE}" > /dev/null 2>&1
if [ $? -ne 0 ]; then
Expand All @@ -95,11 +95,11 @@ generate_client_certs() {
CLIENT_DIRECTORY=$1
CLIENT_CERTIFICATE=${CLIENT_DIRECTORY}/client_cert.pem
CLIENT_CSR=${CLIENT_DIRECTORY}/client_cert.csr
CLIENT_PRIV_KEY=${CLIENT_DIRECTORY}/client_private_key.pem
CLIENT_PRIV_KEY=${CLIENT_DIRECTORY}/client_priv_key.pem

CA_DIRECTORY=$2
CA_CERTIFICATE=${CA_DIRECTORY}/ca_cert.pem
CA_PRIV_KEY=${CA_DIRECTORY}/ca_private_key.pem
CA_PRIV_KEY=${CA_DIRECTORY}/ca_priv_key.pem

if [ ! -f "${CLIENT_CSR}" ]; then
mkdir -p "${CLIENT_DIRECTORY}" > /dev/null 2>&1
Expand All @@ -116,14 +116,14 @@ generate_client_certs() {
openssl req -new \
-key "${CLIENT_PRIV_KEY}" \
-out "${CLIENT_CSR}" \
-subj "/C=UK/ST=Parsec /L=Parsec/O=Parsec/CN=parsec.com" > /dev/null 2>&1
-subj "/C=UK/ST=Parsec /L=Parsec/O=Parsec/CN=parsec_client.com" > /dev/null 2>&1
if [ $? -ne 0 ]; then
echo "FAILED TO GENERATE CERTIFICATE REQUEST"
exit 1
fi

# Generate certificate
openssl x509 -req -in "${CLIENT_CSR}" \
openssl x509 -req -days 1000 -in "${CLIENT_CSR}" \
-CA "${CA_CERTIFICATE}" -CAkey "${CA_PRIV_KEY}" \
-CAcreateserial -out "${CLIENT_CERTIFICATE}" > /dev/null 2>&1
if [ $? -ne 0 ]; then
Expand Down