There it is.
This commit is contained in:
parent
e7d44a152e
commit
b524f113dc
43
1_generateCA.sh
Executable file
43
1_generateCA.sh
Executable file
@ -0,0 +1,43 @@
|
||||
#!/bin/bash
|
||||
echo "###################"
|
||||
echo "# CA generation #"
|
||||
echo -e "###################\n"
|
||||
|
||||
## CA Private key
|
||||
echo -n "Where to save your CA key file? ($PWD/CA.key): "
|
||||
read temp
|
||||
|
||||
if [ -n "$temp" ]
|
||||
then
|
||||
save=$temp
|
||||
else
|
||||
save="$PWD/CA.key"
|
||||
fi
|
||||
CAkey=$save
|
||||
openssl genrsa -aes256 -out $save 8192
|
||||
|
||||
|
||||
## CA Certificate
|
||||
echo -n "Where to save your CA certificate? ($PWD/CA.crt): "
|
||||
read temp
|
||||
|
||||
if [ -n "$temp" ]
|
||||
then
|
||||
save=$temp
|
||||
else
|
||||
save="$PWD/CA.crt"
|
||||
fi
|
||||
|
||||
echo -n "How many days should the certificate be valid? (3650): "
|
||||
read temp
|
||||
|
||||
if [[ $temp =~ ^[0-9]+$ ]]
|
||||
then
|
||||
days=$temp
|
||||
else
|
||||
days=3650
|
||||
fi
|
||||
echo -e "\033[01;33mPlease enter some information about the CA.\033[00m"
|
||||
openssl req -new -x509 -days $days -key $CAkey -out $save
|
||||
|
||||
|
73
2_generateServCert.sh
Executable file
73
2_generateServCert.sh
Executable file
@ -0,0 +1,73 @@
|
||||
#!/bin/bash
|
||||
|
||||
## Server private key
|
||||
echo -n "Where to save your server's key file? ($PWD/ding_server.key): "
|
||||
read temp
|
||||
|
||||
if [ -n "$temp" ]
|
||||
then
|
||||
save=$temp
|
||||
else
|
||||
save="$PWD/ding_server.key"
|
||||
fi
|
||||
key=$save
|
||||
openssl genrsa -out $save 4096
|
||||
|
||||
|
||||
## CSR
|
||||
echo -n "Where to save your Certificate Signing Request (CSR)? ($PWD/ding_server.csr): "
|
||||
read temp
|
||||
|
||||
if [ -n "$temp" ]
|
||||
then
|
||||
save=$temp
|
||||
else
|
||||
save="$PWD/ding_server.csr"
|
||||
fi
|
||||
csr=$save
|
||||
echo -e "\033[01;33mPlease enter some information. THEY MUST BE DIFFERENT FROM THE CA's INFORMATION.\033[00m"
|
||||
openssl req -new -key $key -out $save -sha512
|
||||
|
||||
|
||||
## Signing
|
||||
echo -n "Path of your CA Certificate? ($PWD/CA.crt): "
|
||||
read temp
|
||||
|
||||
if [ -n "$temp" ]
|
||||
then
|
||||
loadCAcrt=$temp
|
||||
else
|
||||
loadCAcrt="$PWD/CA.crt"
|
||||
fi
|
||||
|
||||
echo -n "Path of your CA key? ($PWD/CA.key): "
|
||||
read temp
|
||||
|
||||
if [ -n "$temp" ]
|
||||
then
|
||||
loadCAkey=$temp
|
||||
else
|
||||
loadCAkey="$PWD/CA.key"
|
||||
fi
|
||||
|
||||
echo -n "Where to save your signed server certificate? ($PWD/ding_server.crt): "
|
||||
read temp
|
||||
|
||||
if [ -n "$temp" ]
|
||||
then
|
||||
save=$temp
|
||||
else
|
||||
save="$PWD/ding_server.crt"
|
||||
fi
|
||||
|
||||
echo -n "How many days should the certificate be valid? (365): "
|
||||
read temp
|
||||
|
||||
if [ -n "$temp" ]
|
||||
then
|
||||
t=$temp
|
||||
else
|
||||
t=365
|
||||
fi
|
||||
openssl x509 -req -in $csr -CA $loadCAcrt -CAkey $loadCAkey -CAcreateserial -out $save -days $t -sha512
|
||||
rm $csr
|
73
3_generateClientCert.sh
Executable file
73
3_generateClientCert.sh
Executable file
@ -0,0 +1,73 @@
|
||||
#!/bin/bash
|
||||
|
||||
## Server private key
|
||||
echo -n "Where to save your client's key file? ($PWD/ding_client.key): "
|
||||
read temp
|
||||
|
||||
if [ -n "$temp" ]
|
||||
then
|
||||
save=$temp
|
||||
else
|
||||
save="$PWD/ding_client.key"
|
||||
fi
|
||||
key=$save
|
||||
openssl genrsa -out $save 4096
|
||||
|
||||
|
||||
## CSR
|
||||
echo -n "Where to save your Certificate Signing Request (CSR)? ($PWD/ding_client.csr): "
|
||||
read temp
|
||||
|
||||
if [ -n "$temp" ]
|
||||
then
|
||||
save=$temp
|
||||
else
|
||||
save="$PWD/ding_client.csr"
|
||||
fi
|
||||
csr=$save
|
||||
echo -e "\033[01;33mPlease enter some information. THEY MUST BE DIFFERENT FROM THE CA's AND SERVER's INFORMATION.\033[00m"
|
||||
openssl req -new -key $key -out $save -sha512
|
||||
|
||||
|
||||
## Signing
|
||||
echo -n "Path of your CA Certificate? ($PWD/CA.crt): "
|
||||
read temp
|
||||
|
||||
if [ -n "$temp" ]
|
||||
then
|
||||
loadCAcrt=$temp
|
||||
else
|
||||
loadCAcrt="$PWD/CA.crt"
|
||||
fi
|
||||
|
||||
echo -n "Path of your CA key? ($PWD/CA.key): "
|
||||
read temp
|
||||
|
||||
if [ -n "$temp" ]
|
||||
then
|
||||
loadCAkey=$temp
|
||||
else
|
||||
loadCAkey="$PWD/CA.key"
|
||||
fi
|
||||
|
||||
echo -n "Where to save your signed client certificate? ($PWD/ding_client.crt): "
|
||||
read temp
|
||||
|
||||
if [ -n "$temp" ]
|
||||
then
|
||||
save=$temp
|
||||
else
|
||||
save="$PWD/ding_client.crt"
|
||||
fi
|
||||
|
||||
echo -n "How many days should the certificate be valid? (365): "
|
||||
read temp
|
||||
|
||||
if [ -n "$temp" ]
|
||||
then
|
||||
t=$temp
|
||||
else
|
||||
t=365
|
||||
fi
|
||||
openssl x509 -req -in $csr -CA $loadCAcrt -CAkey $loadCAkey -CAcreateserial -out $save -days $t -sha512
|
||||
rm $csr
|
23
README.md
Normal file
23
README.md
Normal file
@ -0,0 +1,23 @@
|
||||
# ding
|
||||
## What is ding?
|
||||
ding is a client-server thing written in python. Its aim is to execute a set of commands remotely which can be set in the server's config file.
|
||||
|
||||
## How does it work?
|
||||
The server awaits the client's commands. A command sent by the client must be defined in the server's config file, else the server won't do anything.
|
||||
|
||||
## What about ding's security?
|
||||
The authentication is done by an SSL Client Certificate signed by an (own generated) Certificate Authority. The scripts for generating a CA and signing a Server/Client Certificate are also in here to make it (relatively) easy. [ You need only to press enter in the most cases, type in some certificate information and entering a previously defined CA password. ]
|
||||
|
||||
|
||||
## Installation
|
||||
In all steps please read carefully, what the generating script want from you.
|
||||
|
||||
1. Run `./1_generateCA.sh` to generate a CA.
|
||||
2. Run `./2_generateServCert.sh` to generate a signed Server Certificate.
|
||||
3. Run `./3_generateClientCert.sh` to generate a signed Client Certificate.
|
||||
4. Move ding\_client, ding\_client.cfg, ding\_client.crt, ding\_client.key to the computer which should be able to send commands to the server.
|
||||
5. Do some configuration on the server and client (ding\_server.cfg, ding\_client.cfg).
|
||||
6. Start the server using `./ding_server`. You may want to put this in a tmux session ([Ctrl+B, D] ;) ).
|
||||
7. Try out the client using `./ding_client <command>`.
|
||||
|
||||
|
82
ding_client
Executable file
82
ding_client
Executable file
@ -0,0 +1,82 @@
|
||||
#!/usr/bin/env python3
|
||||
import sys, ssl, socket
|
||||
import configparser
|
||||
|
||||
CONFIG = "ding_client.cfg"
|
||||
|
||||
def readConfig():
|
||||
cfg = configparser.SafeConfigParser()
|
||||
try:
|
||||
cfg.read(CONFIG)
|
||||
|
||||
global host, port, cafile, certfile, keyfile
|
||||
|
||||
host = cfg.get("Client", "host")
|
||||
port = int(cfg.get("Client", "port"))
|
||||
|
||||
cafile = cfg.get("Client", "cafile")
|
||||
certfile = cfg.get("Client", "certfile")
|
||||
keyfile = cfg.get("Client", "keyfile")
|
||||
except configparser.NoSectionError:
|
||||
print("No suitable config found. Expecting some config in", CONFIG)
|
||||
quit(3)
|
||||
|
||||
|
||||
def send(conn, cmd):
|
||||
|
||||
global exitcode
|
||||
|
||||
conn.connect((host, port))
|
||||
buf = conn.recv(1024)
|
||||
if(buf == b"OK 1337\n"):
|
||||
conn.sendall(cmd)
|
||||
buf = conn.recv(1024)
|
||||
if(buf == b"OK CMD"):
|
||||
exitcode = 0
|
||||
elif(buf == b"ERR NO_CMD"):
|
||||
print("Error. Server said: The command doesn't exist/isn't set.", file=sys.stderr)
|
||||
exitcode = 1
|
||||
elif(buf == b"ERR CMD_ERR"):
|
||||
print("Error. Server said: The command doesn't work because the file doesn't exist on the server.")
|
||||
exitcode = 2
|
||||
|
||||
else:
|
||||
conn.sendall(b"NO.")
|
||||
print("The server seems to be crazy. Nothing sent.", file=sys.stderr)
|
||||
|
||||
conn.close()
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
try:
|
||||
context = ssl.SSLContext(ssl.PROTOCOL_TLS)
|
||||
context.verify_mode = ssl.CERT_REQUIRED
|
||||
context.load_verify_locations(cafile)
|
||||
context.load_cert_chain(certfile=certfile, keyfile=keyfile)
|
||||
except FileNotFoundError as e:
|
||||
print(e)
|
||||
print("Please check your paths in the config file. (Have you forgotten to generate the Certificates?)", sep="", file=sys.stderr)
|
||||
quit(2)
|
||||
|
||||
conn = context.wrap_socket(socket.socket())
|
||||
|
||||
|
||||
try:
|
||||
send(conn, bytes(sys.argv[1], sys.stdin.encoding))
|
||||
except IndexError:
|
||||
print(sys.argv[0], ": Missing argument.\nSyntax: ", sys.argv[0], " <COMMAND>", file=sys.stderr)
|
||||
except ConnectionRefusedError:
|
||||
print("Connection refused.", file=sys.stderr)
|
||||
quit(1)
|
||||
except ssl.SSLError:
|
||||
print("Wrong certificate.", file=sys.stderr);
|
||||
quit(3)
|
||||
|
||||
|
||||
|
||||
if(__name__ == "__main__"):
|
||||
readConfig()
|
||||
main()
|
||||
quit(exitcode)
|
||||
|
10
ding_client.cfg
Normal file
10
ding_client.cfg
Normal file
@ -0,0 +1,10 @@
|
||||
[Client]
|
||||
host=localhost
|
||||
port=13573
|
||||
|
||||
|
||||
cafile=CA.crt
|
||||
#Client Certificate/key signed by the CA above
|
||||
certfile=ding_client.crt
|
||||
keyfile=ding_client.key
|
||||
|
127
ding_server
Executable file
127
ding_server
Executable file
@ -0,0 +1,127 @@
|
||||
#!/usr/bin/env python3
|
||||
import ssl, socket, subprocess, time
|
||||
import configparser
|
||||
|
||||
CONFIG = "ding_server.cfg"
|
||||
|
||||
def getTimestamp():
|
||||
t = "[" + time.strftime("%Y-%m-%d %H:%M:%S") + "]"
|
||||
return t
|
||||
|
||||
def execFromConfig(option):
|
||||
cfg = configparser.SafeConfigParser()
|
||||
cfg.read(CONFIG)
|
||||
|
||||
try:
|
||||
cmd = cfg.get("Commands", option).replace("\"", "").replace("\'", "")
|
||||
cmd = cmd.split(" ")
|
||||
try:
|
||||
subprocess.Popen(cmd)
|
||||
return 0
|
||||
|
||||
except FileNotFoundError:
|
||||
print(getTimestamp(), "Can't execute", cmd, ". File not found.")
|
||||
return 2
|
||||
|
||||
except configparser.NoOptionError:
|
||||
print(getTimestamp(), "No execution set:", option)
|
||||
return 1
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
while True:
|
||||
newsocket, fromaddr = bindsocket.accept()
|
||||
try:
|
||||
connstream = context.wrap_socket(newsocket, server_side=True)
|
||||
print(getTimestamp(), "Incoming connection:", fromaddr[0])
|
||||
connstream.send(b"OK 1337\n")
|
||||
|
||||
con_loop = True
|
||||
while con_loop:
|
||||
try:
|
||||
buf = connstream.recv(1024)
|
||||
if not buf: break
|
||||
buf = buf.decode("utf-8").upper()
|
||||
except ssl.SSLEOFError:
|
||||
print(getTimestamp(), "SSL-EOF-Error.")
|
||||
con_loop = False
|
||||
except ConnectionResetError:
|
||||
print(getTimestamp(), "Connection reset.")
|
||||
serve()
|
||||
|
||||
print(getTimestamp(), " ", fromaddr[0], ": ", buf, sep="")
|
||||
|
||||
retval = execFromConfig(buf)
|
||||
if(retval == 0):
|
||||
connstream.send(b"OK CMD")
|
||||
elif(retval == 1):
|
||||
connstream.send(b"ERR NO_CMD")
|
||||
elif(retval == 2):
|
||||
connstream.send(b"ERR CMD_ERR")
|
||||
|
||||
|
||||
except ssl.SSLError as e:
|
||||
print(getTimestamp(), e)
|
||||
|
||||
except EOFError:
|
||||
print(getTimestamp(), "EOF")
|
||||
|
||||
def init():
|
||||
|
||||
global host, port, cafile, certfile, keyfile, context, bindsocket
|
||||
|
||||
cfg = configparser.SafeConfigParser()
|
||||
cfg.read(CONFIG)
|
||||
|
||||
try:
|
||||
host=cfg.get("Server", "host").replace("\"","").replace("\'","")
|
||||
port=int(cfg.get("Server", "port").replace("\"","").replace("\'",""))
|
||||
cafile=cfg.get("Security", "cafile").replace("\"","").replace("\'","")
|
||||
certfile=cfg.get("Security", "certfile").replace("\"","").replace("\'","")
|
||||
keyfile=cfg.get("Security", "keyfile").replace("\"","").replace("\'","")
|
||||
except configparser.NoOptionError as e:
|
||||
print("Error in configuration file:", e)
|
||||
quit(1)
|
||||
|
||||
|
||||
try:
|
||||
context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH, cafile=cafile)
|
||||
context.load_cert_chain(certfile=certfile, keyfile=keyfile)
|
||||
context.verify_mode = ssl.CERT_REQUIRED
|
||||
context.load_verify_locations(cafile=cafile)
|
||||
|
||||
except FileNotFoundError as e:
|
||||
print(e)
|
||||
print("Please check your paths in the config file. (Have you forgotten to generate the Certificates?)")
|
||||
quit(2)
|
||||
|
||||
try:
|
||||
bindsocket = socket.socket()
|
||||
bindsocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
bindsocket.bind((host, port))
|
||||
bindsocket.listen(5)
|
||||
except socket.gaierror:
|
||||
print("Error: Hostname error. Name or service not known.")
|
||||
quit(1)
|
||||
except PermissionError:
|
||||
print("Error: Can't bind for port number ", port, ". Permission denied.", sep="")
|
||||
quit(1)
|
||||
|
||||
print("Running ding server on ", host, ":", port,
|
||||
"\nCAFile: ", cafile,
|
||||
"\nCertfile: ", certfile,
|
||||
"\nKeyfile: ", keyfile,
|
||||
"\n===========",
|
||||
sep="")
|
||||
|
||||
|
||||
if(__name__ == "__main__"):
|
||||
|
||||
try:
|
||||
init()
|
||||
main()
|
||||
except KeyboardInterrupt:
|
||||
print("\r\rServer stopped.")
|
||||
|
19
ding_server.cfg
Normal file
19
ding_server.cfg
Normal file
@ -0,0 +1,19 @@
|
||||
[Server]
|
||||
host=localhost
|
||||
port=13573
|
||||
|
||||
[Security]
|
||||
# Certificate of the OWN CA
|
||||
cafile=CA.crt
|
||||
|
||||
# Server's certificate [signed by the CA above]
|
||||
certfile=ding_server.crt
|
||||
|
||||
# Server's private key
|
||||
keyfile=ding_server.key
|
||||
|
||||
|
||||
[Commands]
|
||||
# Syntax:
|
||||
# SERVER_COMMAND: Command --which --should_be --executed
|
||||
lock: xscreensaver-command -lock
|
Loading…
Reference in New Issue
Block a user