/verify_sig

Exercise TCP server to verify an RSA signature using minimal crypto libraries

Primary LanguageGo

This was an exercise, please do not use this for any real world applications.

Choices and Rational

Where possible, I tried to write any cryptographic functions myself instead of using libraries.

Because of this and the time limitation, I have only supported the use of PEM certificates, as the default ouput form from OpenSSL, although if a different certificate type is given, the error will explicitly ask the user to check the certificate is a valid PEM certificate. My server will also only support the use of RSA and SHA256 due to time limitations.

I chose to use a basic TCP server, as this allows us to easily handle concurrent connections, as well as easily returning outputs to the clients due to the stateful nature of the protocol. The server is simply listening for TCP connections on the chosen port, and so a standard byte stream can be sent to the server followed by ===EOF=== to signify the end of the transmission. Below details a script to easily enable this.

Build

The server binary can be built by running the build script whilst in the root dir of the repo.

┌[supinie@ubuntu] [/dev/pts/0] [main ⚡] 
└[~/git/verify_sig]> ./build

Running the server

The server can be run by executing the sig_verify_server binary in the bin dir of the repo (this will be generated by the build script above).

┌[supinie@ubuntu] [/dev/pts/1] [main ⚡] 
└[~/git/verify_sig]> bin/sig_verify_server
Listening on 0.0.0.0:34803

If no argument is passed, then the server will listen on a random available local port, otherwise a port can be specified using the -p flag.

┌[supinie@ubuntu] [/dev/pts/1] [main ⚡] 
└[~/git/verify_sig]> bin/sig_verify_server -p 34803
Listening on 0.0.0.0:34803

A help menu can also be displayed using the -h flag.

┌[supinie@ubuntu] [/dev/pts/0] [main] 
└[~/git/verify_sig]> bin/sig_verify_server -h
Usage of bin/sig_verify_server:
  -p int
    	Choose the port for the server to listen on. Default will be a random available port.
  -v	Specify the verbosity of the outputs. This will give detailed feedback on the validity of every certificate check.

Sending a script to the server

A client can send a script to the server simply using the client_script in the root dir. This takes the arguments of the file to send, the address of the server, and the port the server is listening on.

┌[supinie@ubuntu] [/dev/pts/1] [main ⚡] [1]
└[~/git/verify_sig]> ./client_script bash_script localhost 34293

This is needed as an EOF string must be sent for the server to recognise the EOF correctly.

Expected outputs from examples

I have included 4 cases as examples of what a client could send - these cover all possibilities of validity of bash script and signature. I have also included one certificate that will properly validate the corresponding client inputs, as well as one valid certificate with no corresponding client request, and a certificate using SHA512 that is unsupported by my server. Below is an example of the server outputs using all 4 client requests:

┌[supinie@ubuntu] [/dev/pts/1] [main] 
└[~/git/verify_sig]> bin/sig_verify_server
Listening on 0.0.0.0:39717
Serving 127.0.0.1:46346
Signature from 127.0.0.1:46346 verified using certificate certificate.pem.
Signature and code from 127.0.0.1:46346 valid, output:
this is a test

End of output from 127.0.0.1:46346, closing connection.
Serving 127.0.0.1:51346
Signature recieved from 127.0.0.1:51346 does not match any local certificates, closing connection.
Serving 127.0.0.1:54036
Signature recieved from 127.0.0.1:54036 does not match any local certificates, closing connection.
Serving 127.0.0.1:57568
Signature from 127.0.0.1:57568 verified using certificate certificate.pem.
Error running bash script sent by 127.0.0.1:57568: exit status 127, closing connection.

Corresponding client requests and outputs:

┌[supinie@ubuntu] [/dev/pts/2] [main] 
└[~/git/verify_sig]> ./client_script test_cases/valid_sig_valid_script localhost 39717
Signature verified, script output:
this is a test
┌[supinie@ubuntu] [/dev/pts/2] [main] 
└[~/git/verify_sig]> ./client_script test_cases/invalid_sig_valid_script localhost 39717
Invalid signature recieved.
┌[supinie@ubuntu] [/dev/pts/2] [main] 
└[~/git/verify_sig]> ./client_script test_cases/invalid_sig_invalid_script localhost 39717
Invalid signature recieved.
┌[supinie@ubuntu] [/dev/pts/2] [main] 
└[~/git/verify_sig]> ./client_script test_cases/valid_sig_invalid_script localhost 39717 
Invalid bash script sent, closing connection.

How test cases were generated

I used the command: openssl req -newkey rsa:4096 -x509 -sha256 -days 365 -nodes -out certs/<certificate>.pem -keyout example_private_keys/<privatekey>.pem to generate the private key and certificates.

Once a test bash script has been written, I used openssl dgst -sha256 -sign example_private_keys/<privatekey>.pem -out example_private_keys/<signature> -hex <bash_script> to create the signature that can be preppended to the file.