Initial commit...

This commit is contained in:
itdominator 2021-07-24 20:29:35 -05:00
parent 58c94cc4e1
commit 5e38b5557d
18 changed files with 1103 additions and 1 deletions

View File

@ -1,3 +1,10 @@
# EzyCA # EzyCA
Easily create Certificate Authorities and sign a server PEM and key for use. Easily create Certificate Authorities and sign a server PEM and key for use.
# Requirements
* Need Python 3+
* Need OpenSSL
* Need PyGObject
# Images
![1 Interface CA.... ](images/pic1.png)
![2 Interface Server Cert.... ](images/pic2.png)

BIN
images/pic1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

BIN
images/pic2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

33
src/__init__.py Normal file
View File

@ -0,0 +1,33 @@
# Python imports
import inspect
# Gtk imports
# Application imports
from utils import Settings
from signal_classes import Signals
class Main:
def __init__(self, args):
settings = Settings()
builder = settings.returnBuilder()
# Gets the methods from the classes and sets to handler.
# Then, builder connects to any signals it needs.
classes = [Signals(settings)]
handlers = {}
for c in classes:
methods = None
try:
methods = inspect.getmembers(c, predicate=inspect.ismethod)
handlers.update(methods)
except Exception as e:
pass
builder.connect_signals(handlers)
window = settings.createWindow()
window.show()

32
src/__main__.py Normal file
View File

@ -0,0 +1,32 @@
#!/usr/bin/python3
# Python imports
import argparse
from setproctitle import setproctitle
# Gtk imports
import gi, faulthandler, signal
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk as gtk
from gi.repository import GLib
# Application imports
from __init__ import Main
if __name__ == "__main__":
try:
setproctitle('EzyCA')
GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, signal.SIGINT, gtk.main_quit)
faulthandler.enable() # For better debug info
parser = argparse.ArgumentParser()
# Add long and short arguments
parser.add_argument("--file", "-f", default="default", help="JUST SOME FILE ARG.")
# Read arguments (If any...)
args = parser.parse_args()
main = Main(args)
gtk.main()
except Exception as e:
print( repr(e) )

View File

@ -0,0 +1,399 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.2 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<object class="GtkImage" id="generate_img">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="stock">gtk-file</property>
<property name="icon_size">3</property>
</object>
<object class="GtkTextBuffer" id="textview_buffer"/>
<object class="GtkApplicationWindow" id="Main_Window">
<property name="width-request">800</property>
<property name="height-request">600</property>
<property name="can-focus">False</property>
<property name="title" translatable="yes">EzyCA</property>
<property name="icon">x509_cert_64x64.png</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="margin-left">10</property>
<property name="label" translatable="yes">Target Directory: </property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkFileChooserButton">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="margin-top">15</property>
<property name="margin-bottom">15</property>
<property name="action">select-folder</property>
<property name="do-overwrite-confirmation">True</property>
<property name="preview-widget-active">False</property>
<property name="use-preview-label">False</property>
<property name="title" translatable="yes">Target Directory...</property>
<signal name="file-set" handler="set_work_directory" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can-focus">False</property>
<property name="xpad">25</property>
<property name="ypad">10</property>
<property name="pixbuf">x509_cert.png</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkNotebook">
<property name="visible">True</property>
<property name="can-focus">True</property>
<child>
<object class="GtkBox" id="ca_entry_vbox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">15</property>
<child>
<object class="GtkEntry">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="max-length">2</property>
<property name="placeholder-text" translatable="yes">Country Name (2 letter code eg, US)</property>
<property name="input-purpose">alpha</property>
<signal name="key-release-event" handler="set_server_country" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkEntry">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="max-length">32</property>
<property name="placeholder-text" translatable="yes">State or Province Name (full name eg, 'North Carolina')</property>
<property name="input-purpose">alpha</property>
<signal name="key-release-event" handler="set_server_state" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkEntry">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="placeholder-text" translatable="yes">Locality/City Name (full name eg, 'Durham')</property>
<property name="input-purpose">alpha</property>
<signal name="key-release-event" handler="set_server_city" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkEntry">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="placeholder-text" translatable="yes">Organization Name (eg, company 'Microsoft')</property>
<property name="input-purpose">alpha</property>
<signal name="key-release-event" handler="set_server_org" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkEntry">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="placeholder-text" translatable="yes">Organizational Unit (eg, division 'Microsoft Developent')</property>
<property name="input-purpose">alpha</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">4</property>
</packing>
</child>
<child>
<object class="GtkEntry">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="placeholder-text" translatable="yes">Common Name (e.g. server FQDN or YOUR name 'Microsoft CA')</property>
<property name="input-purpose">alpha</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">5</property>
</packing>
</child>
<child>
<object class="GtkEntry">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="placeholder-text" translatable="yes">Email Address (eg, 'no-reply@microsoft.com')</property>
<property name="input-purpose">email</property>
<signal name="key-release-event" handler="set_server_email" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">6</property>
</packing>
</child>
</object>
<packing>
<property name="tab-expand">True</property>
</packing>
</child>
<child type="tab">
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">CA Conf</property>
</object>
<packing>
<property name="tab-fill">False</property>
</packing>
</child>
<child>
<object class="GtkBox" id="server_entry_vbox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">15</property>
<child>
<object class="GtkEntry" id="svrCountry">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="max-length">2</property>
<property name="placeholder-text" translatable="yes">Country Name (2 letter code eg, US)</property>
<property name="input-purpose">alpha</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="svrState">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="max-length">32</property>
<property name="placeholder-text" translatable="yes">State or Province Name (full name eg, 'North Carolina')</property>
<property name="input-purpose">alpha</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="svrCity">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="placeholder-text" translatable="yes">Locality/City Name (full name eg, 'Durham')</property>
<property name="input-purpose">alpha</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="svrOrg">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="placeholder-text" translatable="yes">Organization Name (eg, company 'Microsoft')</property>
<property name="input-purpose">alpha</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkEntry">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="placeholder-text" translatable="yes">Common Name (e.g. server FQDN or YOUR name 'Microsoft Test Server')</property>
<property name="input-purpose">alpha</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">4</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="svrEmail">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="placeholder-text" translatable="yes">Email Address (eg, 'no-reply@microsoft.com')</property>
<property name="input-purpose">email</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">5</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="ypad">10</property>
<property name="label" translatable="yes">Below, add domain names each on a new line...</property>
<property name="wrap">True</property>
<property name="track-visited-links">False</property>
<attributes>
<attribute name="underline" value="True"/>
<attribute name="foreground" value="#ffffa3a34848"/>
</attributes>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">6</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="shadow-type">in</property>
<property name="overlay-scrolling">False</property>
<child>
<object class="GtkTextView">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="buffer">textview_buffer</property>
<property name="accepts-tab">False</property>
<property name="input-purpose">alpha</property>
<property name="monospace">True</property>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">7</property>
</packing>
</child>
</object>
<packing>
<property name="position">1</property>
<property name="tab-expand">True</property>
</packing>
</child>
<child type="tab">
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Server Conf</property>
</object>
<packing>
<property name="position">1</property>
<property name="tab-fill">False</property>
</packing>
</child>
<child>
<placeholder/>
</child>
<child type="tab">
<placeholder/>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton">
<property name="label" translatable="yes">Generate</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="margin-left">10</property>
<property name="margin-right">10</property>
<property name="margin-top">15</property>
<property name="margin-bottom">15</property>
<property name="image">generate_img</property>
<property name="use-underline">True</property>
<property name="always-show-image">True</property>
<signal name="clicked" handler="generate_ca_and_server_certs" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
</object>
</interface>

View File

@ -0,0 +1,19 @@
/* * {
background: rgba(0, 0, 0, 0.14);
background: rgba(0, 0, 0, 1);
color: rgba(255, 255, 255, 1);
}
notebook > header {
border-color: rgba(0, 232, 255, 0.64);
}
* selection {
background-color: rgba(75, 0, 116, 0.65);
color: rgba(255, 255, 255, 0.5);
}
textarea.view {
border-style: solid;
border-color: rgba(255, 255, 255, 1);
} */

BIN
src/resources/x509_cert.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -0,0 +1,130 @@
# Python imports
import threading, subprocess, os
# Gtk imports
# Application imports
from .mixins import *
def threaded(fn):
def wrapper(*args, **kwargs):
threading.Thread(target=fn, args=args, kwargs=kwargs).start()
return wrapper
class Signals(Utils, CAGenerator, ServerCertGenerator):
def __init__(self, settings):
self.settings = settings
self.builder = self.settings.returnBuilder()
self.ca_entry_vbox = self.builder.get_object("ca_entry_vbox")
self.server_entry_vbox = self.builder.get_object("server_entry_vbox")
self.textview_buffer = self.builder.get_object("textview_buffer")
self.target_path = None
def set_work_directory(self, widget, data=None):
self.target_path = widget.get_filename()
def generate_ca_and_server_certs(self, widget):
print("Generating CA and signed Server Certs...")
ca_data = []
server_cert_data = []
ca_entries = self.ca_entry_vbox.get_children()
server_entries = self.server_entry_vbox.get_children()
self.fill_data_block(ca_data, ca_entries)
self.fill_data_block(server_cert_data, server_entries)
buffer = self.textview_buffer
domains = buffer.get_text(
buffer.get_start_iter(),
buffer.get_end_iter(),
True
).strip().split("\n")
assert(self.target_path != None and self.target_path != ''), "A target work directory must be set!"
assert(len(ca_data) == len(ca_entries)), "All CA entries must be filled!"
assert(len(server_cert_data) == (len(server_entries) - 2) ), "All Server Cert entries must be filled!"
self.step_1_create_ca_settings(self.target_path, ca_data)
self.step_2_create_signing_ca_settings(self.target_path, ca_data)
self.step_3_create_openssl_server_cert_settings(self.target_path, server_cert_data, domains)
self.step_4_generate_all(self.target_path)
def step_4_generate_all(self, target_path):
print("Step 4: Running generation process...")
opensslcacnf = target_path + "/openssl-ca-settings.cnf"
opensslsigningcasettingscnf = target_path + "/openssl-signing-ca-settings.cnf"
opensslservercnf = target_path + "/openssl-server-cert.cnf"
signedcertsdir = target_path + "/signed_certs"
cacertpem = target_path + "/cacert.pem"
servercertpem = target_path + "/servercert.pem"
servercertcsr = target_path + "/servercert.csr"
indexfile = target_path + "/index.txt"
serialfile = target_path + "/serial.txt"
os.chdir(target_path)
os.mkdir(signedcertsdir)
with open(indexfile, 'a') as f:
f.close()
with open(serialfile, 'w') as f:
f.write("01")
print("\t\tCreating CA cert key...")
# openssl req -batch -x509 -days 10000 -config ./openssl-ca.cnf -newkey
# rsa:4096 -sha256 -nodes -out cacert.pem -outform PEM
command = ["openssl", "req", "-batch", "-x509", "-days", "10000", "-config", opensslcacnf, "-newkey", "rsa:4096",
"-sha256", "-nodes", "-out", cacertpem, "-outform", "PEM"]
proc = subprocess.Popen(command, stdout=subprocess.PIPE)
proc.wait()
# You can dump the certificate with the following.
# openssl x509 -in cacert.pem -text -noout
print("\t\tCreating Server cert key pare...")
# openssl req -batch -config ./openssl-server.cnf -newkey rsa:2048
# -sha256 -nodes -out servercert.csr -outform PEM
command = ["openssl", "req", "-batch", "-config", opensslservercnf, "-newkey", "rsa:4096", "-sha256", "-nodes",
"-out", servercertcsr, "-outform", "PEM"]
proc = subprocess.Popen(command, stdout=subprocess.PIPE)
proc.wait()
# You can inspect.
# openssl req -text -noout -verify -in servercert.csr
print("\t\tCertifying Server cert with our CA...")
# openssl ca -batch -config ./openssl-ca.cnf -policy signing_policy
# -extensions signing_req -out servercert.pem -infiles servercert.csr
command = ["openssl", "ca", "-batch", "-config", opensslsigningcasettingscnf,
"-policy", "signing_policy", "-extensions", "signing_req", "-out",
servercertpem, "-infiles", "servercert.csr"]
proc = subprocess.Popen(command, stdout=subprocess.PIPE)
proc.wait()
# Finally, you can inspect your freshly minted certificate with the following:
# openssl x509 -in servercert.pem -text -noout
def set_server_country(self, widget, data=None):
self.builder.get_object("svrCountry").set_text(widget.get_text().strip())
def set_server_state(self, widget, data=None):
self.builder.get_object("svrState").set_text(widget.get_text().strip())
def set_server_city(self, widget, data=None):
self.builder.get_object("svrCity").set_text(widget.get_text().strip())
def set_server_org(self, widget, data=None):
self.builder.get_object("svrOrg").set_text(widget.get_text().strip())
def set_server_email(self, widget, data=None):
self.builder.get_object("svrEmail").set_text(widget.get_text().strip())

View File

@ -0,0 +1,5 @@
"""
Gtk Bound Signal Module
"""
from .mixins import *
from .Signals import Signals

View File

@ -0,0 +1,210 @@
# Python imports
import threading, subprocess, os
# Gtk imports
# Application imports
class CAGenerator:
"""Empty docstring for CAGenerator"""
ca_settings = """# ----------------------------- NOTE
# Remember to disable very bottom when generating first ca key and pem.
# Check notes at [ CA_default ] section as well!
# ----------------------------- NOTE
HOME = {}
RANDFILE = $ENV::HOME/.rnd
####################################################################
[ ca ]
default_ca = CA_default # The default ca section
[ CA_default ]
default_days = 3000 # How long to certify for
default_crl_days = 3000 # How long before next CRL
default_md = sha256 # Use public key default MD
preserve = no # Keep passed DN ordering
x509_extensions = ca_extensions # The extensions to add to the cert
email_in_dn = no # Don't concat the email in the DN
copy_extensions = copy # Required to copy SANs from CSR to cert
# ca_default_additional_block_marker
####################################################################
[ req ]
default_bits = 4096
default_keyfile = cakey.pem
distinguished_name = ca_distinguished_name
x509_extensions = ca_extensions
string_mask = utf8only
####################################################################
[ ca_distinguished_name ]
countryName = Country Name (2 letter code)
countryName_default = {}
stateOrProvinceName = State or Province Name (full name eg, 'North Carolina')
stateOrProvinceName_default = {}
localityName = Locality/City Name (full name eg, 'Durham')
localityName_default = {}
organizationName = Organization Name (eg, company 'Microsoft')
organizationName_default = {}
organizationalUnitName = Organizational Unit (eg, division)
organizationalUnitName_default = {}
commonName = Common Name (e.g. server FQDN or YOUR name)
commonName_default = {}
emailAddress = Email Address (eg, 'no-reply@microsoft.com')
emailAddress_default = {}
####################################################################
[ ca_extensions ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always, issuer
basicConstraints = critical, CA:true
keyUsage = keyCertSign, cRLSign
# Extensions for a typical CA
# PKIX recommendation.
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical,CA:true
# Key usage: This is typical for a CA certificate. However since it will prevent
# it being used as an test self-signed certificate it is best left out by default.
# keyUsage = cRLSign, keyCertSign
# Some might want this also...
# nsCertType = sslCA, emailCA
# subjectAltName=email:copy # Include email address in subject alt name: another PKIX recommendation
# issuerAltName=issuer:copy # Copy issuer details
# DER hex encoding of an extension: Beware experts only!
# obj=DER:02:03 # Where 'obj' is a standard or added object
# basicConstraints= critical, DER:30:03:01:01:FF # You can even override a supported extension.
####################################################################
[ crl_ext ]
# CRL extensions. Only issuerAltName and authorityKeyIdentifier make any sense in a CRL.
# issuerAltName = issuer:copy
authorityKeyIdentifier = keyid:always
####################################################################
[ proxy_cert_ext ]
# These extensions should be added when creating a proxy certificate
# This goes against PKIX guidelines but some CAs do it and some software
# requires this to avoid interpreting an end user certificate as a CA.
basicConstraints=CA:FALSE
# Here are some examples of the usage of nsCertType. If it is omitted
# the certificate can be used for anything *except* object signing.
# nsCertType = server # This is OK for an SSL server.
# nsCertType = objsign # For an object signing certificate this would be used.
# nsCertType = client, email # For normal client using this is typical.
# nsCertType = client, email, objsign # For everything including object signing.
# This is typical in keyUsage for a client certificate.
# keyUsage = nonRepudiation, digitalSignature, keyEncipherment
# This will be displayed in Netscape's comment listbox.
nsComment = 'OpenSSL Generated Certificate'
# PKIX recommendations harmless if included in all certificates.
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
# This stuff is for subjectAltName and issuerAltname.
# subjectAltName = email:copy # Import the email address.
# subjectAltName = email:move # An alternative to produce certificates that aren't deprecated according to PKIX.
# issuerAltName = issuer:copy # Copy subject details
#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem
#nsBaseUrl
#nsRevocationUrl
#nsRenewalUrl
#nsCaPolicyUrl
#nsSslServerName
# This really needs to be in place for it to be a proxy certificate.
proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo
####################################################################
[ tsa ]
default_tsa = tsa_config1 # The default TSA section (Which is set below...)
[ tsa_config1 ]
# These are used by the TSA reply generation only.
dir = /etc/ssl # TSA root directory
serial = $dir/tsaserial # The current serial number
crypto_device = builtin # OpenSSL engine to use for signing
signer_cert = $dir/tsacert.pem # The TSA signing certificate (optional)
certs = $dir/cacert.pem # Certificate chain to include in reply (optional)
signer_key = $dir/private/tsakey.pem # The TSA private key (optional)
signer_digest = sha256 # Signing digest to use. (optional)
default_policy = tsa_policy1 # Policy if request did not specify it (optional)
other_policies = tsa_policy2, tsa_policy3 # Acceptable policies (optional)
digests = sha1, sha256, sha384, sha512 # Acceptable message digests
accuracy = secs:1, millisecs:500, microsecs:100 # (optional)
clock_precision_digits = 0 # Number of digits after dot. (optional)
ordering = yes # Is ordering defined for timestamps? (optional, default: no)
tsa_name = yes # Must the TSA name be included in the reply? (optional, default: no)
ess_cert_id_chain = no # Must the ESS cert id chain be included? (optional, default: no)
ess_cert_id_alg = sha1 # Algorithm to compute certificate identifier (optional, default: sha1)
# ca_signing_block_marker
"""
ca_default_additional_block = """base_dir = {}
certificate = $base_dir/cacert.pem # The CA certifcate
private_key = $base_dir/cakey.pem # The CA private key
new_certs_dir = $base_dir/signed_certs/ # Location for new certs after signing
database = $base_dir/index.txt # Database index file
serial = $base_dir/serial.txt # The current serial number
unique_subject = no # Set to 'no' to allow creation of several certificates with same subject.
"""
ca_signing_block = """####################################################################
[ signing_policy ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ signing_req ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
basicConstraints = CA:FALSE
keyUsage = digitalSignature, keyEncipherment
"""
def step_1_create_ca_settings(self, path, data):
print("Step 1: Creating CA Settings...")
all_data = [path] + data
fpath = path + "/openssl-ca-settings.cnf"
output_str = self.ca_settings.format(*all_data)
with open(fpath, "w") as f:
f.write(output_str)
def step_2_create_signing_ca_settings(self, path, data):
print("Step 2: Creating Signing CA Settings...")
all_data = [path] + data
fpath = path + "/openssl-signing-ca-settings.cnf"
output_str = self.ca_settings.format(*all_data)
ca_block = self.ca_default_additional_block.format(path)
output_str = output_str.replace("# ca_default_additional_block_marker", ca_block)
output_str = output_str.replace("# ca_signing_block_marker", self.ca_signing_block)
with open(fpath, "w") as f:
f.write(output_str)

View File

@ -0,0 +1,83 @@
# Python imports
import threading, subprocess, os
# Gtk imports
# Application imports
class ServerCertGenerator:
"""Empty docstring for ServerCertGenerator"""
server_cert_settings = """# ----------------------------- NOTE
HOME = {}
RANDFILE = $ENV::HOME/.rnd
####################################################################
[ req ]
default_bits = 2048
default_keyfile = privkey.pem
distinguished_name = server_distinguished_name
req_extensions = server_req_extensions
string_mask = utf8only
####################################################################
[ server_distinguished_name ]
countryName = Country Name (2 letter code)
countryName_default = {}
stateOrProvinceName = State or Province Name (full name eg, 'North Carolina')
stateOrProvinceName_default = {}
localityName = Locality/City Name (full name eg, 'Durham')
localityName_default = {}
organizationName = Organization Name (eg, company 'Microsoft')
organizationName_default = {}
commonName = Common Name (e.g. server FQDN or YOUR name)
commonName_default = {}
emailAddress = Email Address (eg, 'no-reply@microsoft.com')
emailAddress_default = {}
####################################################################
[ server_req_extensions ]
subjectKeyIdentifier = hash
basicConstraints = CA:FALSE
keyUsage = digitalSignature, keyEncipherment
subjectAltName = @alternate_names
nsComment = "OpenSSL Generated Certificate"
####################################################################
[ alternate_names ]
# alternate_names_marker
# If you are developing and need to use your workstation as a server, then you may
# need to do the following for Chrome. Otherwise Chrome may complain a Common Name
# is invalid (ERR_CERT_COMMON_NAME_INVALID). I'm not sure what the relationship is
# between an IP address in the SAN and a CN in this instance.
# IPv4 localhost
IP.1 = 0.0.0.0
IP.2 = 127.0.0.1
# IPv6 localhost
IP.2 = ::1
"""
def step_3_create_openssl_server_cert_settings(self, path, data, domains):
print("Step 3: Creating OpenSSL Server Cert Settings...")
all_data = [path] + data
fpath = path + "/openssl-server-cert.cnf"
output_str = self.server_cert_settings.format(*all_data)
domain_block = ""
i = 1
for domain in domains:
domain_block += "DNS.{} = {}".format(*(i, domain + "\n"))
i += 1
output_str = output_str.replace("# alternate_names_marker", domain_block)
with open(fpath, "w") as f:
f.write(output_str)

View File

@ -0,0 +1,35 @@
# Python imports
import threading, subprocess, os
# Gtk imports
# Application imports
class Utils:
"""Empty docstring for Utils"""
def fill_data_block(self, target, data):
for entry in data:
text = ''
if hasattr(entry, "get_children"):
entry = entry.get_children()[0]
if hasattr(entry, "get_text"):
text = entry.get_text().strip()
if text != '' and text != 'Below, add domain names each on a new line...':
target.append(text)
def getClipboardData(self):
proc = subprocess.Popen(['xclip','-selection', 'clipboard', '-o'], stdout=subprocess.PIPE)
retcode = proc.wait()
data = proc.stdout.read()
return data.decode("utf-8").strip()
def setClipboardData(self, data):
proc = subprocess.Popen(['xclip','-selection','clipboard'], stdin=subprocess.PIPE)
proc.stdin.write(data)
proc.stdin.close()
retcode = proc.wait()

View File

@ -0,0 +1,3 @@
from .Utils import Utils
from .CAGenerator import CAGenerator
from .ServerCertGenerator import ServerCertGenerator

56
src/utils/Logger.py Normal file
View File

@ -0,0 +1,56 @@
# Python imports
import os, logging
# Application imports
class Logger:
def __init__(self):
pass
def get_logger(self, loggerName = "NO_LOGGER_NAME_PASSED", createFile = True):
"""
Create a new logging object and return it.
:note:
NOSET # Don't know the actual log level of this... (defaulting or literally none?)
Log Levels (From least to most)
Type Value
CRITICAL 50
ERROR 40
WARNING 30
INFO 20
DEBUG 10
:param loggerName: Sets the name of the logger object. (Used in log lines)
:param createFile: Whether we create a log file or just pump to terminal
:return: the logging object we created
"""
globalLogLvl = logging.DEBUG # Keep this at highest so that handlers can filter to their desired levels
chLogLevel = logging.CRITICAL # Prety musch the only one we change ever
fhLogLevel = logging.DEBUG
log = logging.getLogger(loggerName)
log.setLevel(globalLogLvl)
# Set our log output styles
fFormatter = logging.Formatter('[%(asctime)s] %(pathname)s:%(lineno)d %(levelname)s - %(message)s', '%m-%d %H:%M:%S')
cFormatter = logging.Formatter('%(pathname)s:%(lineno)d] %(levelname)s - %(message)s')
ch = logging.StreamHandler()
ch.setLevel(level=chLogLevel)
ch.setFormatter(cFormatter)
log.addHandler(ch)
if createFile:
folder = "logs"
file = folder + "/application.log"
if not os.path.exists(folder):
os.mkdir(folder)
fh = logging.FileHandler(file)
fh.setLevel(level=fhLogLevel)
fh.setFormatter(fFormatter)
log.addHandler(fh)
return log

84
src/utils/Settings.py Normal file
View File

@ -0,0 +1,84 @@
# Python imports
import os
# Gtk imports
import gi, cairo
gi.require_version('Gtk', '3.0')
gi.require_version('Gdk', '3.0')
from gi.repository import Gtk as gtk
from gi.repository import Gdk as gdk
# Application imports
class Settings:
def __init__(self):
self.SCRIPT_PTH = os.path.dirname(os.path.realpath(__file__)) + "/"
self.builder = gtk.Builder()
self.builder.add_from_file(self.SCRIPT_PTH + "../resources/Main_Window.glade")
# 'Filters'
self.office = ('.doc', '.docx', '.xls', '.xlsx', '.xlt', '.xltx', '.xlm',
'.ppt', 'pptx', '.pps', '.ppsx', '.odt', '.rtf')
self.vids = ('.mkv', '.avi', '.flv', '.mov', '.m4v', '.mpg', '.wmv',
'.mpeg', '.mp4', '.webm')
self.txt = ('.txt', '.text', '.sh', '.cfg', '.conf')
self.music = ('.psf', '.mp3', '.ogg' , '.flac')
self.images = ('.png', '.jpg', '.jpeg', '.gif')
self.pdf = ('.pdf')
def createWindow(self):
# Get window and connect signals
window = self.builder.get_object("Main_Window")
window.connect("delete-event", gtk.main_quit)
self.setWindowData(window, False)
return window
def setWindowData(self, window, paintable):
screen = window.get_screen()
visual = screen.get_rgba_visual()
if visual != None and screen.is_composited():
window.set_visual(visual)
# bind css file
cssProvider = gtk.CssProvider()
cssProvider.load_from_path(self.SCRIPT_PTH + '../resources/stylesheet.css')
screen = gdk.Screen.get_default()
styleContext = gtk.StyleContext()
styleContext.add_provider_for_screen(screen, cssProvider, gtk.STYLE_PROVIDER_PRIORITY_USER)
window.set_app_paintable(paintable)
if paintable:
window.connect("draw", self.area_draw)
def getMonitorData(self):
screen = self.builder.get_object("Main_Window").get_screen()
monitors = []
for m in range(screen.get_n_monitors()):
monitors.append(screen.get_monitor_geometry(m))
for monitor in monitors:
print("{}x{}+{}+{}".format(monitor.width, monitor.height, monitor.x, monitor.y))
return monitors
def area_draw(self, widget, cr):
cr.set_source_rgba(0, 0, 0, 0.54)
cr.set_operator(cairo.OPERATOR_SOURCE)
cr.paint()
cr.set_operator(cairo.OPERATOR_OVER)
def returnBuilder(self): return self.builder
# Filter returns
def returnOfficeFilter(self): return self.office
def returnVidsFilter(self): return self.vids
def returnTextFilter(self): return self.txt
def returnMusicFilter(self): return self.music
def returnImagesFilter(self): return self.images
def returnPdfFilter(self): return self.pdf

6
src/utils/__init__.py Normal file
View File

@ -0,0 +1,6 @@
"""
Utils module
"""
from .Logger import Logger
from .Settings import Settings