added tls code to client

This commit is contained in:
Aidan Hahn 2019-05-19 12:21:00 -07:00
parent 5d66a9880c
commit 3021a1d405
No known key found for this signature in database
GPG key ID: 327711E983899316
2 changed files with 96 additions and 51 deletions

View file

@ -51,7 +51,7 @@ openssl genrsa -passout pass:${CLTCAPASS} -aes256 -out $CLIENT_PATH/private.key
echo "[+] Generating Client signing request" echo "[+] Generating Client signing request"
openssl req -passin pass:${CLTCAPASS} -new -key $CLIENT_PATH/private.key -out $CLIENT_PATH/request.csr -subj "/CN=${CLIENT_CN}" openssl req -passin pass:${CLTCAPASS} -new -key $CLIENT_PATH/private.key -out $CLIENT_PATH/request.csr -subj "/CN=${CLIENT_CN}"
echo "[+] Generating Client certificate " echo "[+] Generating Client certificate "
openssl x509 -req -passin pass:${CLTCAPASS} -days 365 -in $CLIENT_PATH/request.csr -CA $CLIENT_PATH/ca.crt -CAkey $CLIENT_PATH/ca.key -set_serial 01 -out $CLIENT_PATH/server.crt openssl x509 -req -passin pass:${CLTCAPASS} -days 365 -in $CLIENT_PATH/request.csr -CA $CLIENT_PATH/ca.crt -CAkey $CLIENT_PATH/ca.key -set_serial 01 -out $CLIENT_PATH/client.crt
echo "[+] Removing passphrase from client key" echo "[+] Removing passphrase from client key"
openssl rsa -passin pass:${CLTCAPASS} -in $CLIENT_PATH/private.key -out $CLIENT_PATH/private.key openssl rsa -passin pass:${CLTCAPASS} -in $CLIENT_PATH/private.key -out $CLIENT_PATH/private.key
@ -61,7 +61,7 @@ openssl genrsa -passout pass:dontusethiskey -aes256 -out $TEST_PATH/private.key
echo "[+] Generating test signing request" echo "[+] Generating test signing request"
openssl req -passin pass:dontusethiskey -new -key $TEST_PATH/private.key -out $TEST_PATH/request.csr -subj "/CN=${DontUseMe}" openssl req -passin pass:dontusethiskey -new -key $TEST_PATH/private.key -out $TEST_PATH/request.csr -subj "/CN=${DontUseMe}"
echo "[+] Generating test certificate " echo "[+] Generating test certificate "
openssl x509 -req -passin pass:dontusethiskey -days 365 -in $TEST_PATH/request.csr -CA $TEST_PATH/ca.crt -CAkey $TEST_PATH/ca.key -set_serial 01 -out $TEST_PATH/server.crt openssl x509 -req -passin pass:dontusethiskey -days 365 -in $TEST_PATH/request.csr -CA $TEST_PATH/ca.crt -CAkey $TEST_PATH/ca.key -set_serial 01 -out $TEST_PATH/test.crt
echo "[+] Removing passphrase from test key" echo "[+] Removing passphrase from test key"
openssl rsa -passin pass:dontusethiskey -in $TEST_PATH/private.key -out $TEST_PATH/private.key openssl rsa -passin pass:dontusethiskey -in $TEST_PATH/private.key -out $TEST_PATH/private.key
@ -75,4 +75,4 @@ echo "[+] creating combine trust store"
cat $SERVER_PATH/ca.crt $CLIENT_PATH/ca.crt > resources/truststore.pem cat $SERVER_PATH/ca.crt $CLIENT_PATH/ca.crt > resources/truststore.pem
echo "[+] initiating gradle build" echo "[+] initiating gradle build"
./gradlew clear build ./gradlew clean build

View file

@ -11,6 +11,13 @@ package JobServ;
import io.grpc.ManagedChannel; import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder; import io.grpc.ManagedChannelBuilder;
import io.grpc.StatusRuntimeException; import io.grpc.StatusRuntimeException;
import io.grpc.netty.GrpcSslContexts;
import io.grpc.netty.NettyChannelBuilder;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import javax.net.ssl.SSLException;
import java.io.File;
import java.util.InputMismatchException; import java.util.InputMismatchException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.logging.Level; import java.util.logging.Level;
@ -23,7 +30,8 @@ import java.util.Scanner;
*/ */
public class JobServClient { public class JobServClient {
/* The client should not use the same logging module as the server. /*
* The client should not use the same logging module as the server.
* In a more robust product the server logging module will take advantage of system level * In a more robust product the server logging module will take advantage of system level
* log aggregators such as journalctl, which the client should not be writing to on the users system * log aggregators such as journalctl, which the client should not be writing to on the users system
*/ */
@ -31,33 +39,49 @@ public class JobServClient {
private final ManagedChannel channel; private final ManagedChannel channel;
/* blockingStub is used when the client needs to block until the server responds /*
* blockingStub is used when the client needs to block until the server responds
* the client doesnt nessesarily need to support asynchronously firing off commands * the client doesnt nessesarily need to support asynchronously firing off commands
* in this shell-like interface it would be disconcerting to get multiple returns out of order * in this shell-like interface it would be disconcerting to get multiple returns out of order
*/ */
private final ShellServerGrpc.ShellServerBlockingStub blockingStub; private final ShellServerGrpc.ShellServerBlockingStub blockingStub;
// Constructor connects to server /*
public JobServClient(String host, int port) { * Constructor
this(ManagedChannelBuilder.forAddress(host, port) * Creates an SslContext from cert, key, and trust store
// TODO: MTLS * Creates a ManagedChannel object from SSL Parameters
.usePlaintext() * Spawns a new blockingStub for network operations with the server
.build()); */
} public JobServClient(String host,
int port,
// private overload of constructor, used in the above constructor String trustStore,
JobServClient(ManagedChannel channel) { String clientCert,
this.channel = channel; String clientPrivateKey) throws SSLException {
blockingStub = ShellServerGrpc.newBlockingStub(channel); SslContextBuilder builder = GrpcSslContexts.forClient();
builder.trustManager(new File(trustStore));
builder.keyManager(new File(clientCert), new File(clientPrivateKey));
this.channel = NettyChannelBuilder.forAddress(host, port)
.sslContext(builder.build())
.build();
blockingStub = ShellServerGrpc.newBlockingStub(this.channel);
} }
/*
* shutdown()
* Gets called when you press cntrl+c
* takes at most 5 seconds to close its connection
*/
public void shutdown() throws InterruptedException { public void shutdown() throws InterruptedException {
channel.shutdown().awaitTermination(5, TimeUnit.SECONDS); channel.shutdown().awaitTermination(5, TimeUnit.SECONDS);
} }
// sends the server a request for output from PID /*
// different from getProcessStatus in output expected from the server * getProcessInfo()
// returns process output as string * sends the server a request for output from the process identified by 'pid'
* returns process output as string
*/
public String getProcessOutput(int pid) { public String getProcessOutput(int pid) {
logger.info("[+] requesting output"); logger.info("[+] requesting output");
@ -77,8 +101,11 @@ public class JobServClient {
return response.getOutput(); return response.getOutput();
} }
// sends the server a command for a new job, blocks until response /*
// returns new pid of job * sendNewJobMessage()
* sends a shell command to the api server
* returns new pid of job
*/
public int sendNewJobMessage(String command) { public int sendNewJobMessage(String command) {
// thought of escaping this, but the vulnerability is only client side, from client user input. // thought of escaping this, but the vulnerability is only client side, from client user input.
logger.info("[+] Sending command to server"); logger.info("[+] Sending command to server");
@ -103,8 +130,11 @@ public class JobServClient {
return response.getPid(); return response.getPid();
} }
// requests running status of job /*
// returns true if job still running else false * getProcessStatus()
* requests running status of process pid
* returns true if process still running else false
*/
public Boolean getProcessStatus(int pid) { public Boolean getProcessStatus(int pid) {
logger.info("[+] Requesting status of a job"); logger.info("[+] Requesting status of a job");
@ -124,9 +154,12 @@ public class JobServClient {
return response.getIsRunning(); return response.getIsRunning();
} }
// sends PID to server expecting the return cod eof a process /*
// function returns a 0-255 return code or 277 if still running * sends PID to server
// or 278 if error in API * returns process exit code
* returns a 0-255 return code or 277 if still running
* or 278 if error in API
*/
public int getProcessReturn(int pid) { public int getProcessReturn(int pid) {
logger.info("[+] Requesting return code of a job"); logger.info("[+] Requesting return code of a job");
@ -146,8 +179,11 @@ public class JobServClient {
return response.getProcessReturnCode(); return response.getProcessReturnCode();
} }
// send a PID to be killed, returns nothing /*
// logs warning if job status comes back still running * killProcess()
* send a PID to be killed, function returns nothing
* logs warning if job status comes back still running
*/
public void killProcess(int pid) { public void killProcess(int pid) {
logger.info("[+] Killing a job"); logger.info("[+] Killing a job");
@ -169,40 +205,49 @@ public class JobServClient {
} }
} }
// Client entrypoint /*
* main()
* Client entrypoint
* Parses arguments and calls the correct function
*/
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
if (args.length == 1 && args[0] == "help"){ if (args.length == 1 && args[0] == "help"){
outputHelp(); outputHelp();
} }
// check args // check args
if (args.length < 3) { if (args.length < 7) {
System.out.println("Usage: $ jobservclient host port command"); System.out.println("Usage: $ ./jobserv-client privatekey, cert, truststore, host, port, command, args");
System.out.println("Or try client --help"); System.out.println("Or try $ ./jobserv-client help");
return; return;
} }
// start client (or fail if port is improperly formatted) // start client
// fails if port is improperly formatted or if an ssl exception occurs
JobServClient client; JobServClient client;
try { try {
client = new JobServClient(args[0], Integer.parseInt(args[1])); client = new JobServClient(args[0], Integer.parseInt(args[1]), args[2], args[1], args[0]);
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
System.out.println("Invalid Port"); System.out.println("Invalid Port");
return; return;
} catch (SSLException e) {
System.out.println(e.getMessage());
return;
} }
// declare up here so that multiple switch cases can use it // declare pid up here so that multiple switch cases can use it
int candidatePid; int candidatePid;
// parse remaining args
switch (args[2]) { switch (args[2]) {
case "new": case "new":
if (args.length < 4) { if (args.length < 7) {
System.out.println("Improper formatting, try client --help"); System.out.println("Improper formatting, try client --help");
break; break;
} }
String command = ""; String command = "";
for (int token = 3; token < args.length; token++) { for (int token = 6; token < args.length; token++) {
command += " " + args[token]; command += " " + args[token];
} }
@ -211,15 +256,15 @@ public class JobServClient {
break; break;
case "output": case "output":
if (args.length != 4) { if (args.length != 7) {
System.out.println("Improper formatting, try client --help"); System.out.println("Improper formatting, try client --help");
break; break;
} }
try { try {
candidatePid = Integer.parseInt(args[3]); candidatePid = Integer.parseInt(args[6]);
} catch (InputMismatchException e) { } catch (InputMismatchException e) {
System.out.println(args[3] + " is not a valid int, much less a valid pid"); System.out.println(args[6] + " is not a valid int, much less a valid pid");
break; break;
} }
@ -228,16 +273,16 @@ public class JobServClient {
break; break;
case "status": case "status":
if (args.length != 4) { if (args.length != 7) {
System.out.println("Improper formatting, try client --help"); System.out.println("Improper formatting, try client --help");
break; break;
} }
try { try {
candidatePid = Integer.parseInt(args[3]); candidatePid = Integer.parseInt(args[6]);
} catch (InputMismatchException e) { } catch (InputMismatchException e) {
System.out.println(args[3] + " is not a valid int, much less a valid pid"); System.out.println(args[6] + " is not a valid int, much less a valid pid");
break; break;
} }
@ -246,16 +291,16 @@ public class JobServClient {
break; break;
case "kill": case "kill":
if (args.length != 4) { if (args.length != 7) {
System.out.println("Improper formatting, try client --help"); System.out.println("Improper formatting, try client --help");
break; break;
} }
try { try {
candidatePid = Integer.parseInt(args[3]); candidatePid = Integer.parseInt(args[6]);
} catch (InputMismatchException e) { } catch (InputMismatchException e) {
System.out.println(args[3] + " is not a valid int, much less a valid pid"); System.out.println(args[6] + " is not a valid int, much less a valid pid");
break; break;
} }
@ -264,16 +309,16 @@ public class JobServClient {
break; break;
case "return": case "return":
if (args.length != 4) { if (args.length != 7) {
System.out.println("Improper formatting, try client --help"); System.out.println("Improper formatting, try client --help");
break; break;
} }
try { try {
candidatePid = Integer.parseInt(args[3]); candidatePid = Integer.parseInt(args[6]);
} catch (InputMismatchException e) { } catch (InputMismatchException e) {
System.out.println(args[3] + " is not a valid int, much less a valid pid"); System.out.println(args[6] + " is not a valid int, much less a valid pid");
break; break;
} }