Credmanager

- Had to make this as was required

Server

- Server-side TLS stream thing

Client

- Client-side stream thing
This commit is contained in:
Tristan B. Velloza Kildaire 2023-04-29 22:04:46 +02:00
parent 679530662f
commit 70053118af
3 changed files with 325 additions and 6 deletions

View File

@ -1,7 +1,7 @@
module cryptstream.streams.client;
import river.core : RiverStream = Stream, StreamException, StreamError;
import core.thread : Thread;
import core.thread : Thread, dur;
import botan.tls.client;
@ -26,6 +26,12 @@ public class CryptClient : RiverStream
*/
private TLSClient botanClient;
// TODO: Setup
private TLSSessionManager sessionManager = new TLSSessionManagerNoop();
private TLSCredentialsManager credentialManager;
private TLSPolicy policy = new TLSPolicy();
private RandomNumberGenerator rng;
/**
* Constructs a new TLS-enabled client stream
* Params:
@ -35,7 +41,14 @@ public class CryptClient : RiverStream
{
this.stream = stream;
this.botanClient = new TLSClient(&tlsOutputHandler);
this.rng = RandomNumberGenerator.makeRng();
import cryptstream.streams.credmanager : CredManager;
this.credentialManager = new CredManager();
// FIXME: Currently we are crashing with a segmentation fault here
this.botanClient = new TLSClient(&tlsOutputHandler, &decryptedInputHandler, &tlsAlertHandler, &tlsHandshakeHandler,
sessionManager, credentialManager, policy, rng);
// TODO: Insert code to init using botan OVER `stream`
@ -54,16 +67,44 @@ public class CryptClient : RiverStream
private void streamReaderWorker()
{
// TODO: Make this size configurable
byte[100] readInto;
byte[500] readInto;
while(true)
{
ulong receivedAmount = stream.read(readInto);
version(unittest)
{
import std.stdio;
import std.conv : to;
writeln("streamReaderWorker(client-side): Transferring "~to!(string)(receivedAmount)~" many bytes over to Botan client...");
writeln("streamReaderWorker(client-side): The bytes are: "~to!(string)(readInto[0..receivedAmount]));
// writeln("streamReaderWorker(): The bytes are (as string): "~cast(string[])readInto[0..receivedAmount]);
}
// TODO: Use the hint byte count returned?
botanClient.receivedData(cast(ubyte*)readInto.ptr, receivedAmount);
}
}
private bool tlsHandshakeHandler(in TLSSession session)
{
// TODO: Implement me
return true;
}
private void decryptedInputHandler(in ubyte[] receivedDecryptedData)
{
// TODO: This is now decrypted and THIS data should be placed
// ... into a buffer in CryptClient that can be read from
// ... via `read/readFully`
}
private void tlsAlertHandler(in TLSAlert alert, in ubyte[] data)
{
}
// NOTE This gets called when the Botan client needs to write to
// ... the underlying output. So If we were to call `botanClient.send`
// ... (which takes in our plaintext), it would encrypt, and then
@ -89,8 +130,10 @@ public class CryptClient : RiverStream
/* Ensure the TLS session is active */
openCheck();
// TODO: Implement me
return 0;
// TODO: It seems we can basically have everything or nothing
// ... so just call read as the method of TLS records does this
// ... to us
return read(toArray);
}
public override ulong write(byte[] fromArray)
@ -136,4 +179,40 @@ public class CryptClient : RiverStream
throw new StreamException(StreamError.CLOSED);
}
}
}
version(unittest)
{
import river.core;
import river.impls : SockStream;
import std.socket;
import std.stdio;
import cryptstream.streams.server;
}
unittest
{
/**
* Setup a server
*/
Address addr = parseAddress("::1", 7057);
writeln("Binding server to: ", addr);
Server server = new Server(addr);
server.start();
Socket endpoint = new Socket(AddressFamily.INET6, SocketType.STREAM, ProtocolType.TCP);
endpoint.connect(addr);
Stream stream = new SockStream(endpoint);
CryptClient client = new CryptClient(stream);
Thread.sleep(dur!("seconds")(3));
client.writeFully(cast(byte[])"ABBA");
while(true){}
}

View File

@ -0,0 +1,83 @@
module cryptstream.streams.credmanager;
import botan.tls.client;
import botan.math.bigint.bigint : BigInt;
public class CredManager : TLSCredentialsManager
{
public override Vector!CertificateStore trustedCertificateAuthorities(in string type, in string context)
{
return super.trustedCertificateAuthorities(type, context);
}
public override void verifyCertificateChain(in string type, in string purported_hostname, const ref Vector!X509Certificate cert_chain)
{
return super.verifyCertificateChain(type, purported_hostname, cert_chain);
}
public override Vector!X509Certificate certChain(const ref Vector!string cert_key_types, in string type, in string context)
{
return super.certChain(cert_key_types, type, context);
}
public override Vector!X509Certificate certChainSingleType(in string cert_key_type, in string type, in string context)
{
return super.certChainSingleType(cert_key_type, type, context);
}
public override PrivateKey privateKeyFor(in X509Certificate cert, in string type, in string context)
{
return super.privateKeyFor(cert, type, context);
}
public override bool attemptSrp(in string type, in string context)
{
return super.attemptSrp(type, context);
}
public override string srpIdentifier(in string type, in string context)
{
return super.srpIdentifier(type, context);
}
public override string srpPassword(in string type, in string context, in string identifier)
{
return super.srpPassword(type, context, identifier);
}
public override bool srpVerifier(in string type,
in string context,
in string identifier,
ref string group_name,
ref BigInt verifier,
ref Vector!ubyte salt,
bool generate_fake_on_unknown)
{
return super.srpVerifier(type, context, identifier, group_name, verifier, salt, generate_fake_on_unknown);
}
public override string pskIdentityHint(in string type, in string context)
{
return super.pskIdentityHint(type, context);
}
public override string pskIdentity(in string type, in string context, in string identity_hint)
{
return super.pskIdentity(type, context, identity_hint);
}
public override bool hasPsk()
{
return super.hasPsk();
}
public override PrivateKey channelPrivateKey(string hostname)
{
return super.channelPrivateKey(hostname);
}
public override SymmetricKey psk(in string type, in string context, in string identity)
{
return super.psk(type, context, identity);
}
}

View File

@ -1,3 +1,160 @@
module cryptstream.streams.server;
import botan.tls.server;
import botan.tls.server;
import river.core;
import river.impls.sock : SockStream;
import core.thread;
import botan.tls.credentials_manager;
public class CryptServerHandle
{
private Stream clientSocket;
private TLSServer server;
// TODO: Setup
private TLSSessionManager sessionManager = new TLSSessionManagerNoop();
private TLSCredentialsManager credentialManager;
private TLSPolicy policy = new TLSPolicy();
private RandomNumberGenerator rng;
/**
* Reads, in its own thread, bytes from the client
* and pushes them into the Botan server
*/
private Thread streamReader;
this(Stream clientSocket)
{
import std.stdio;
writeln("HOL");
this.rng = RandomNumberGenerator.makeRng();
import cryptstream.streams.credmanager : CredManager;
this.credentialManager = new CredManager();
this.clientSocket = clientSocket;
version(unittest)
{
import std.stdio;
writeln("CryptServer ctor(): Before TLSServer creation");
}
this.server = new TLSServer(&tlsOutputHandler, &decryptedInputHandler, &tlsAlertHandler, &tlsHandshakeHandler,
sessionManager, credentialManager, policy, rng);
version(unittest)
{
import std.stdio;
writeln("CryptServer ctor(): AFTER TLSServer creation");
}
this.streamReader = new Thread(&streamReaderWorker);
this.streamReader.start();
}
private void streamReaderWorker()
{
// TODO: Make this size configurable
byte[500] readInto;
while(true)
{
ulong receivedAmount = clientSocket.read(readInto);
version(unittest)
{
import std.stdio;
import std.conv : to;
writeln("streamReaderWorker(server-side): Transferring "~to!(string)(receivedAmount)~" many bytes over to Botan server...");
writeln("streamReaderWorker(server-side): The bytes are: "~to!(string)(readInto[0..receivedAmount]));
}
// TODO: Use the hint byte count returned?
server.receivedData(cast(ubyte*)readInto.ptr, receivedAmount);
}
}
private bool tlsHandshakeHandler(in TLSSession session)
{
// TODO: Implement me
return true;
}
private void decryptedInputHandler(in ubyte[] receivedDecryptedData)
{
// TODO: This is now decrypted and THIS data should be placed
// ... into a buffer in CryptServer that can be read from
// ... via `read/readFully`
}
private void tlsAlertHandler(in TLSAlert alert, in ubyte[] data)
{
}
// NOTE This gets called when the Botan server needs to write to
// ... the underlying output. So If we were to call `server.send`
// ... (which takes in our plaintext), it would encrypt, and then
// ... push the encrypted payload into this method here below
// ... (implying we should write to our underlying stream here)
private void tlsOutputHandler(in ubyte[] dataOut)
{
clientSocket.writeFully(cast(byte[])dataOut);
}
}
version(unittest)
{
import std.socket;
import cryptstream.streams.client : CryptClient;
import core.thread;
public class Server : Thread
{
private Socket serverSocket;
this(Address bindAddr)
{
serverSocket = new Socket(bindAddr.addressFamily(), SocketType.STREAM, ProtocolType.TCP);
serverSocket.bind(bindAddr);
serverSocket.listen(0);
super(&begin);
}
private void begin()
{
while(true)
{
Socket clientSocket = serverSocket.accept();
Stream clientStream = new SockStream(clientSocket);
CryptServerHandle cryptoClientStream = new CryptServerHandle(clientStream);
Connection clientConnection = new Connection(cryptoClientStream);
clientConnection.start();
}
}
}
public class Connection : Thread
{
private CryptServerHandle client;
this(CryptServerHandle client)
{
this.client = client;
super(&worker);
}
private void worker()
{
while(true)
{
// TODO: Do something here with the client
import std.stdio;
writeln("Hello I am connection");
Thread.sleep(dur!("seconds")(10));
}
}
}
}