Puppet config erstellt und CA-Managment auf certtool umgestellt
Dieser Commit ist enthalten in:
Ursprung
8a89a0c56d
Commit
c62b8461c7
|
@ -0,0 +1 @@
|
|||
../ca/ca.pem
|
|
@ -0,0 +1,151 @@
|
|||
# This file is commonly accessed via passdb {} or userdb {} section in
|
||||
# conf.d/auth-ldap.conf.ext
|
||||
|
||||
# This file is opened as root, so it should be owned by root and mode 0600.
|
||||
#
|
||||
# http://wiki2.dovecot.org/AuthDatabase/LDAP
|
||||
#
|
||||
# NOTE: If you're not using authentication binds, you'll need to give
|
||||
# dovecot-auth read access to userPassword field in the LDAP server.
|
||||
# With OpenLDAP this is done by modifying /etc/ldap/slapd.conf. There should
|
||||
# already be something like this:
|
||||
|
||||
# access to attribute=userPassword
|
||||
# by dn="<dovecot's dn>" read # add this
|
||||
# by anonymous auth
|
||||
# by self write
|
||||
# by * none
|
||||
|
||||
# Space separated list of LDAP hosts to use. host:port is allowed too.
|
||||
#hosts =
|
||||
|
||||
# LDAP URIs to use. You can use this instead of hosts list. Note that this
|
||||
# setting isn't supported by all LDAP libraries.
|
||||
#uris =
|
||||
|
||||
# Distinguished Name - the username used to login to the LDAP server.
|
||||
# Leave it commented out to bind anonymously (useful with auth_bind=yes).
|
||||
#dn =
|
||||
|
||||
# Password for LDAP server, if dn is specified.
|
||||
#dnpass =
|
||||
|
||||
# Use SASL binding instead of the simple binding. Note that this changes
|
||||
# ldap_version automatically to be 3 if it's lower.
|
||||
#sasl_bind = no
|
||||
# SASL mechanism name to use.
|
||||
#sasl_mech =
|
||||
# SASL realm to use.
|
||||
#sasl_realm =
|
||||
# SASL authorization ID, ie. the dnpass is for this "master user", but the
|
||||
# dn is still the logged in user. Normally you want to keep this empty.
|
||||
#sasl_authz_id =
|
||||
|
||||
# Use TLS to connect to the LDAP server.
|
||||
#tls = no
|
||||
# TLS options, currently supported only with OpenLDAP:
|
||||
#tls_ca_cert_file =
|
||||
#tls_ca_cert_dir =
|
||||
#tls_cipher_suite =
|
||||
# TLS cert/key is used only if LDAP server requires a client certificate.
|
||||
#tls_cert_file =
|
||||
#tls_key_file =
|
||||
# Valid values: never, hard, demand, allow, try
|
||||
#tls_require_cert =
|
||||
|
||||
# Use the given ldaprc path.
|
||||
#ldaprc_path =
|
||||
|
||||
# LDAP library debug level as specified by LDAP_DEBUG_* in ldap_log.h.
|
||||
# -1 = everything. You may need to recompile OpenLDAP with debugging enabled
|
||||
# to get enough output.
|
||||
#debug_level = 0
|
||||
|
||||
# Use authentication binding for verifying password's validity. This works by
|
||||
# logging into LDAP server using the username and password given by client.
|
||||
# The pass_filter is used to find the DN for the user. Note that the pass_attrs
|
||||
# is still used, only the password field is ignored in it. Before doing any
|
||||
# search, the binding is switched back to the default DN.
|
||||
#auth_bind = no
|
||||
|
||||
# If authentication binding is used, you can save one LDAP request per login
|
||||
# if users' DN can be specified with a common template. The template can use
|
||||
# the standard %variables (see user_filter). Note that you can't
|
||||
# use any pass_attrs if you use this setting.
|
||||
#
|
||||
# If you use this setting, it's a good idea to use a different
|
||||
# dovecot-ldap.conf.ext for userdb (it can even be a symlink, just as long as
|
||||
# the filename is different in userdb's args). That way one connection is used
|
||||
# only for LDAP binds and another connection is used for user lookups.
|
||||
# Otherwise the binding is changed to the default DN before each user lookup.
|
||||
#
|
||||
# For example:
|
||||
# auth_bind_userdn = cn=%u,ou=people,o=org
|
||||
#
|
||||
#auth_bind_userdn =
|
||||
|
||||
# LDAP protocol version to use. Likely 2 or 3.
|
||||
#ldap_version = 3
|
||||
|
||||
# LDAP base. %variables can be used here.
|
||||
# For example: dc=mail, dc=example, dc=org
|
||||
base =
|
||||
|
||||
# Dereference: never, searching, finding, always
|
||||
#deref = never
|
||||
|
||||
# Search scope: base, onelevel, subtree
|
||||
#scope = subtree
|
||||
|
||||
# User attributes are given in LDAP-name=dovecot-internal-name list. The
|
||||
# internal names are:
|
||||
# uid - System UID
|
||||
# gid - System GID
|
||||
# home - Home directory
|
||||
# mail - Mail location
|
||||
#
|
||||
# There are also other special fields which can be returned, see
|
||||
# http://wiki2.dovecot.org/UserDatabase/ExtraFields
|
||||
#user_attrs = homeDirectory=home,uidNumber=uid,gidNumber=gid
|
||||
|
||||
# Filter for user lookup. Some variables can be used (see
|
||||
# http://wiki2.dovecot.org/Variables for full list):
|
||||
# %u - username
|
||||
# %n - user part in user@domain, same as %u if there's no domain
|
||||
# %d - domain part in user@domain, empty if user there's no domain
|
||||
#user_filter = (&(objectClass=posixAccount)(uid=%u))
|
||||
|
||||
# Password checking attributes:
|
||||
# user: Virtual user name (user@domain), if you wish to change the
|
||||
# user-given username to something else
|
||||
# password: Password, may optionally start with {type}, eg. {crypt}
|
||||
# There are also other special fields which can be returned, see
|
||||
# http://wiki2.dovecot.org/PasswordDatabase/ExtraFields
|
||||
#pass_attrs = uid=user,userPassword=password
|
||||
|
||||
# If you wish to avoid two LDAP lookups (passdb + userdb), you can use
|
||||
# userdb prefetch instead of userdb ldap in dovecot.conf. In that case you'll
|
||||
# also have to include user_attrs in pass_attrs field prefixed with "userdb_"
|
||||
# string. For example:
|
||||
#pass_attrs = uid=user,userPassword=password,\
|
||||
# homeDirectory=userdb_home,uidNumber=userdb_uid,gidNumber=userdb_gid
|
||||
|
||||
# Filter for password lookups
|
||||
#pass_filter = (&(objectClass=posixAccount)(uid=%u))
|
||||
|
||||
# Attributes and filter to get a list of all users
|
||||
#iterate_attrs = uid=user
|
||||
#iterate_filter = (objectClass=posixAccount)
|
||||
|
||||
# Default password scheme. "{scheme}" before password overrides this.
|
||||
# List of supported schemes is in: http://wiki2.dovecot.org/Authentication
|
||||
#default_pass_scheme = CRYPT
|
||||
|
||||
# By default all LDAP lookups are performed by the auth master process.
|
||||
# If blocking=yes, auth worker processes are used to perform the lookups.
|
||||
# Each auth worker process creates its own LDAP connection so this can
|
||||
# increase parallelism. With blocking=no the auth master process can
|
||||
# keep 8 requests pipelined for the LDAP connection, while with blocking=yes
|
||||
# each connection has a maximum of 1 request running. For small systems the
|
||||
# blocking=no is sufficient and uses less resources.
|
||||
#blocking = no
|
|
@ -0,0 +1,20 @@
|
|||
organization = "Berufsbildungswerk Südhessen gGmbH"
|
||||
unit = "Kaufmännischer Bereich"
|
||||
unit = "IT"
|
||||
locality = "Karben"
|
||||
state = "Hessen"
|
||||
country = DE
|
||||
cn = "BBW Root Zertifikat"
|
||||
dc = "bbw"
|
||||
dn_oid = "2.5.4.9 Am Heroldsrain 1" # Straße
|
||||
dn_oid = "2.5.4.17 61184" # Postleitzahl
|
||||
activation_date = "2018-03-01 00:00:00 UTC"
|
||||
expiration_date = "2028-03-01 00:00:00 UTC"
|
||||
ca
|
||||
signing_key
|
||||
crl_signing_key
|
||||
ocsp_signing_key
|
||||
policy1_txt = "Internes Zertifikat"
|
||||
nc_permit_dns = bbw
|
||||
honor_crq_extensions
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
export typ=rsa
|
||||
export laenge=4096
|
||||
export crtdir=certs
|
|
@ -0,0 +1,4 @@
|
|||
#!/bin/bash
|
||||
source ./config
|
||||
certtool -p --null-password --bits=$laenge --$typ --outfile=ca.key -8
|
||||
certtool -s --null-password --load-privkey=ca.key --outfile=ca.pem --template=ca.txt
|
|
@ -0,0 +1,9 @@
|
|||
#!/bin/bash
|
||||
source ./config
|
||||
if [ -z "$1" ]; then
|
||||
echo -e "nicht genügend Argumente\nnutzung: $0 domain"
|
||||
exit 1
|
||||
fi
|
||||
sed "s/DOMAIN/$1/g" normcert.txt >$crtdir/$1.txt
|
||||
certtool -p --null-password --bits=$laenge --$typ --outfile=$crtdir/$1.key -8
|
||||
certtool -c --null-password --load-ca-privkey=ca.key --load-ca-certificate=ca.pem --load-privkey=$crtdir/$1.key --outfile=$crtdir/$1.pem --template=$crtdir/$1.txt
|
|
@ -0,0 +1,4 @@
|
|||
#!/bin/bash
|
||||
source ./config
|
||||
certtool -p --null-password --bits=$laenge --$typ --outfile=puppet.key -8
|
||||
certtool -c --null-password --load-ca-privkey=ca.key --load-ca-certificate=ca.pem --load-privkey=puppet.key --outfile=puppet.pem --template=puppet.txt
|
|
@ -0,0 +1,16 @@
|
|||
organization = "Berufsbildungswerk Südhessen gGmbH"
|
||||
unit = "Kaufmännischer Bereich"
|
||||
unit = "IT"
|
||||
locality = "Karben"
|
||||
state = "Hessen"
|
||||
country = DE
|
||||
dc = "bbw"
|
||||
dn_oid = "2.5.4.9 Am Heroldsrain 1" # Straße
|
||||
dn_oid = "2.5.4.17 61184" # Postleitzahl
|
||||
activation_date = "2018-03-01 00:00:00 UTC"
|
||||
expiration_date = "2028-03-01 00:00:00 UTC"
|
||||
tls_www_server
|
||||
encryption_key
|
||||
cn = "DOMAIN"
|
||||
dns_name = "DOMAIN"
|
||||
dns_name = "www.DOMAIN"
|
|
@ -0,0 +1,14 @@
|
|||
organization = "Berufsbildungswerk Südhessen gGmbH"
|
||||
unit = "Kaufmännischer Bereich"
|
||||
unit = "IT"
|
||||
locality = "Karben"
|
||||
state = "Hessen"
|
||||
country = DE
|
||||
cn = "Puppet Zertifikat"
|
||||
dc = "bbw"
|
||||
dn_oid = "2.5.4.9 Am Heroldsrain 1" # Straße
|
||||
dn_oid = "2.5.4.17 61184" # Postleitzahl
|
||||
activation_date = "2018-03-01 00:00:00 UTC"
|
||||
expiration_date = "2028-03-01 00:00:00 UTC"
|
||||
ca
|
||||
honor_crq_extensions
|
|
@ -0,0 +1,134 @@
|
|||
|
||||
mod "oxc-dovecot", "1.0.1"
|
||||
mod "pcfens-ca_cert", "1.7.1"
|
||||
|
||||
class { "ca_cert": }
|
||||
|
||||
ca_cert::ca { "GlobalSign-OrgSSL-Intermediate":
|
||||
ensure => "trusted",
|
||||
source => "puppet:///module/bbwmodul/bbwca.crt",
|
||||
}
|
||||
|
||||
class {"apt":
|
||||
update => {
|
||||
frequency => "daily",
|
||||
},
|
||||
}
|
||||
class { "apt::backports":}
|
||||
|
||||
|
||||
node "zeus", "hades" {
|
||||
apt::source { "fusiondirectory":
|
||||
location => "http://repos.fusiondirectory.org/fusiondirectory-current/debian-jessie/",
|
||||
release => "stable",
|
||||
repos => "main",
|
||||
key => {
|
||||
"id" => "D744D55EACDA69FF",
|
||||
"server" => "pgp.mit.edu",
|
||||
},
|
||||
include => {
|
||||
"deb" => true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
node "zeus" {
|
||||
class { "postgresql::globals":
|
||||
encoding => "UTF-8",
|
||||
locale => "de_DE.UTF-8",
|
||||
}
|
||||
class { "postgresql::server":
|
||||
}
|
||||
postgresql::server::db { "icinga":
|
||||
user => "icinga",
|
||||
password => postgresql_password("icinga", ""),
|
||||
}
|
||||
postgresql::server::db { "sogo":
|
||||
user => "sogo",
|
||||
password => postgresql_password("sogo", ""),
|
||||
}
|
||||
postgresql::server::role { "tobieseb":
|
||||
password_hash => postgresql_password("tobieseb", "mypasswd"),
|
||||
superuser => true,
|
||||
}
|
||||
postgresql::server::pg_hba_rule { "sogo access rule":
|
||||
description => "Gibt sogo zugriff auf die datenbank",
|
||||
type => "host",
|
||||
database => "sogo",
|
||||
user => "sogo",
|
||||
address => "10.x.x.3",
|
||||
auth_method => "md5",
|
||||
}
|
||||
postgresql::server::pg_hba_rule { "icinga access rule":
|
||||
description => "Gibt Icinga zugriff auf die datenbank",
|
||||
type => "host",
|
||||
database => "icinga",
|
||||
user => "icinga",
|
||||
address => "10.x.x.3",
|
||||
auth_method => "md5",
|
||||
}
|
||||
postgresql::server::pg_hba_rule { "tobieseb access rule":
|
||||
description => "Gibt dem Superuser Zugriff auf die datenbank",
|
||||
type => "host",
|
||||
user => "tobieseb",
|
||||
address => "172.16.34.0/23",
|
||||
auth_method => "md5",
|
||||
}
|
||||
file { "/etc/dovecot/private/dovecot-ldap.conf":
|
||||
mode => 000,
|
||||
owner => "",
|
||||
group => "",
|
||||
source => "puppet:///modules/bbwmodul/dovecot-ldap.conf",
|
||||
}
|
||||
class { "dovecot":
|
||||
"plugins" => [ "imap" ],
|
||||
"config" => {
|
||||
"protocols" => "imap",
|
||||
"listen" => "*, ::",
|
||||
},
|
||||
"configs" => {
|
||||
"auth-ldap" => {
|
||||
"passdb" => {
|
||||
"driver" => "ldap",
|
||||
"args" => "/etc/dovecot/private/dovecot-ldap.conf",
|
||||
},
|
||||
"userdb" => {
|
||||
"driver" => "ldap",
|
||||
"args" => "/etc/dovecot/private/dovecot-ldap.conf",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
node "poseidon" {
|
||||
}
|
||||
node "hades" {
|
||||
class { "apache": }
|
||||
class { "apache::mod::ssl": }
|
||||
apache2::vhost { "sogo.bbw http":
|
||||
"port" => "80",
|
||||
redirect_status => "permanent",
|
||||
redirect_dest => "https://sogo.bbw/",
|
||||
"servername" => "sogo.bbw",
|
||||
"ssl" => false,
|
||||
}
|
||||
apache2::vhost { "sogo.bbw https":
|
||||
"port" => "443",
|
||||
"docroot" => "",
|
||||
"servername" => "sogo.bbw",
|
||||
"ssl" => true,
|
||||
}
|
||||
apache2::vhost { "management.bbw http":
|
||||
"port" => "80",
|
||||
redirect_status => "permanent",
|
||||
redirect_dest => "https://management.bbw/",
|
||||
"servername" => "management.bbw",
|
||||
"ssl" => false,
|
||||
}
|
||||
apache2::vhost { "management.bbw https":
|
||||
"port" => "80",
|
||||
"docroot" => "",
|
||||
"servername" => "management.bbw",
|
||||
"ssl" => true,
|
||||
}
|
||||
}
|
Binäre Datei nicht angezeigt.
339
ca/myca.py
339
ca/myca.py
|
@ -1,339 +0,0 @@
|
|||
#!/usr/bin/python3
|
||||
import argparse
|
||||
import sqlite3
|
||||
from cryptography import x509
|
||||
from cryptography.hazmat.primitives.asymmetric import rsa
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
from cryptography.hazmat.primitives import hashes
|
||||
from cryptography.hazmat.primitives.serialization import PrivateFormat, NoEncryption, BestAvailableEncryption, load_pem_private_key
|
||||
from cryptography.x509.oid import NameOID
|
||||
from cryptography.hazmat.primitives.serialization import Encoding
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
import datetime
|
||||
|
||||
|
||||
def parser_factory():
|
||||
parser = argparse.ArgumentParser(description="Programm zur Administration von Zertifikaten")
|
||||
parser.add_argument("--db", type=str, help="Datenbank die benutzt wird.", default="certificates.sqlite3")
|
||||
subparser = parser.add_subparsers(dest="aktion", title="Kommandos", )
|
||||
newca = subparser.add_parser("newca", help="erstellt ein neues CA-Zertifikat")
|
||||
request = subparser.add_parser("request", help="erstellt eine Zertifikatsanfrage")
|
||||
sign = subparser.add_parser("sign", help="TBI Signiert eine Zertifikatsanfrage")
|
||||
config = subparser.add_parser("config", help="TBI")
|
||||
for kommando in [ newca, request]:
|
||||
kommando.add_argument("--length", type=int, help="Schlüssellänge des Zertifikats, sollte ein Exponent von 2 und größer als 1024 sein", default=4096, dest="länge")
|
||||
kommando.add_argument("--commonname", type=str, help="Name des Besitzers", required=True, dest="cn")
|
||||
kommando.add_argument("--location", help="Stadt", dest="l")
|
||||
kommando.add_argument("--state", help="Bundesland/Kanton", dest="st")
|
||||
kommando.add_argument("--organization", help="Firma", dest="o")
|
||||
kommando.add_argument("--ou", help="Abteilung", dest="ou")
|
||||
kommando.add_argument("--country", help="Land", dest="c")
|
||||
kommando.add_argument("--street", help="Straße", dest="street")
|
||||
request.add_argument(
|
||||
"--san",
|
||||
help="Alternativer Name für die Resource, kann eine Emailadresse, URI oder eine Domain sein. sonderzeichen in Domains sollten bereits mittels IDNA umkodiert worden sein.",
|
||||
action="append",
|
||||
dest="san",
|
||||
nargs="?",
|
||||
)
|
||||
request.add_argument("-s", dest="server", action="store_true", help="Serverzertifikat")
|
||||
request.add_argument("-cl", dest="client", action="store_true", help="Clientzertifikat")
|
||||
request.add_argument("-co", dest="code", action="store_true", help="Codesignaturzertifikat")
|
||||
request.add_argument("-e", dest="email", action="store_true", help="Emailzertifikat")
|
||||
request.add_argument("--ca", dest="ca", help="Certificate Authority, Zertifizierungstelle mit optionaler Pfadlänge", nargs="?", type=int)
|
||||
newca.add_argument("tage", type=int, help="Tage die das Zertifikat gültig ist")
|
||||
return parser
|
||||
|
||||
def initdb(cursor):
|
||||
cursor.execute("CREATE TABLE IF NOT EXISTS \"certificates\" ( `commonname` TEXT NOT NULL, `serial` TEXT NOT NULL UNIQUE, `publickey` TEXT NOT NULL, `privatkey` TEXT NOT NULL UNIQUE, `parent` integer, `ca` INTEGER NOT NULL, PRIMARY KEY(`commonname`), FOREIGN KEY(`parent`) REFERENCES `certificates`(`serial`) ) WITHOUT ROWID")
|
||||
cursor.execute("CREATE TABLE IF NOT EXISTS \"requests\" ( `commonname` TEXT NOT NULL, `csr` TEXT NOT NULL UNIQUE, `privatkey` TEXT NOT NULL, PRIMARY KEY(`commonname`) )")
|
||||
|
||||
def print_wrp(text):
|
||||
def wrapper(*t):
|
||||
print(text)
|
||||
return wrapper
|
||||
|
||||
def str_exttype(exttype):
|
||||
if isinstance(exttype, x509.BasicConstraints):
|
||||
if not exttype.ca:
|
||||
return "Keine CA"
|
||||
if exttype.path_length in [None, 0]:
|
||||
return "CA, unendliche Pfadlänge"
|
||||
return "CA, Pfadlänge {}".format(exttype.path_length)
|
||||
elif isinstance(exttype, x509.ExtendedKeyUsage):
|
||||
text = ""
|
||||
for usage in exttype:
|
||||
text += usage._name + ", "
|
||||
return text[:-2]
|
||||
elif isinstance(exttype, x509.SubjectAlternativeName):
|
||||
text = ""
|
||||
for an in exttype._general_names:
|
||||
text += an._value + ", "
|
||||
return text[:-2]
|
||||
else:
|
||||
return repr(exttype)
|
||||
|
||||
def print_info(cert):
|
||||
for name in cert.subject.rdns:
|
||||
for oid in name:
|
||||
print("{}: {}".format(oid._oid._name, oid.value))
|
||||
for extension in cert.extensions:
|
||||
kritisch = "kritisch"
|
||||
if not extension.critical:
|
||||
kritisch = "nicht" + kritisch
|
||||
print("{}({}): {}".format(extension.oid._name, kritisch, str_exttype(extension.value)))
|
||||
|
||||
class Certwrapper:
|
||||
def __init__(self, backend):
|
||||
self.threads = ThreadPoolExecutor(3, "cryptoops")
|
||||
self.anfragetemplate = x509.CertificateSigningRequestBuilder()
|
||||
self.backend = backend
|
||||
|
||||
def gencert(self, länge):
|
||||
return self.threads.submit(rsa.generate_private_key, 65537, länge, self.backend)
|
||||
|
||||
def sign(self, subject, issuer, time_valid, public_key, privat_ca_key, extensions=None, ca_key=None):
|
||||
if not extensions:
|
||||
extensions = []
|
||||
builder = x509.CertificateBuilder()
|
||||
jetzt = datetime.datetime.now()
|
||||
builder = builder.serial_number(x509.random_serial_number())
|
||||
builder = builder.not_valid_before(jetzt)
|
||||
builder = builder.not_valid_after(jetzt + time_valid)
|
||||
builder = builder.subject_name(subject)
|
||||
builder = builder.issuer_name(issuer)
|
||||
builder = builder.public_key(public_key)
|
||||
for extension in extensions:
|
||||
builder = builder.add_extension(extension, True)
|
||||
if ca_key:
|
||||
builder = builder.add_extension(x509.AuthorityKeyIdentifier(ca_key.fingerprint(hashes.SHA512()), None, None), True)
|
||||
return builder.sign(privat_ca_key, hashes.SHA512(), self.backend)
|
||||
|
||||
def request(self, subject, erweiterungen=[], certlänge=4096):
|
||||
cert = self.gencert(certlänge)
|
||||
anfrage = self.anfragetemplate.subject_name(subject)
|
||||
for erweiterung in erweiterungen:
|
||||
anfrage = anfrage.add_extension(erweiterung, True)
|
||||
anfrage = anfrage.sign(cert.result(), hashes.SHA512(), self.backend)
|
||||
return {
|
||||
"privat": cert.result(),
|
||||
"csr": anfrage
|
||||
}
|
||||
|
||||
|
||||
class DBbackend:
|
||||
def __init__(self, connection):
|
||||
self.connection = connection
|
||||
|
||||
def insert_certificate(self, commonname: str, serial, publickey, privatkey, ca: bool):
|
||||
self.connection.execute(
|
||||
"INSERT INTO `certificates`(commonname, serial, publickey, privatkey, ca) VALUES (?, ?, ?, ?, ?)",
|
||||
(
|
||||
commonname,
|
||||
serial,
|
||||
publickey,
|
||||
privatkey,
|
||||
ca
|
||||
)
|
||||
)
|
||||
self.connection.commit()
|
||||
|
||||
def insert_request(self, commonname, cst, privatkey):
|
||||
self.connection.execute(
|
||||
"INSERT INTO `requests`(commonname, csr, privatkey) VALUES (?, ?, ?)",
|
||||
(
|
||||
commonname,
|
||||
csr,
|
||||
privatkey,
|
||||
)
|
||||
)
|
||||
self.connection.commit()
|
||||
|
||||
|
||||
class Commands:
|
||||
def __init__(self, backend, connection, args):
|
||||
self.backend = backend
|
||||
self.threads = ThreadPoolExecutor(3, "cryptoops")
|
||||
self.connection = connection
|
||||
self.connection.row_factory = sqlite3.Row
|
||||
self.cursor = connection.cursor()
|
||||
self.arguments = args
|
||||
self.wrapper = Certwrapper(backend)
|
||||
self.db = DBbackend(connection)
|
||||
|
||||
def get(self, name):
|
||||
try:
|
||||
return self.__getattribute__(name)
|
||||
except (AttributeError, TypeError):
|
||||
return None
|
||||
|
||||
def fragen(self, fragen, typ=tuple):
|
||||
antworten = []
|
||||
for id in fragen:
|
||||
antworten.append(typ(id, self.frage(fragen[id], False)))
|
||||
return antworten
|
||||
|
||||
def frage(self, text, typ=str):
|
||||
while True:
|
||||
antwort = input("{}: ".format(text))
|
||||
try:
|
||||
return typ(antwort)
|
||||
except TypeError:
|
||||
print("Falsche Eingabe")
|
||||
continue
|
||||
|
||||
def parsedn(self, dn):
|
||||
namen = []
|
||||
if dn.cn:
|
||||
namen.append(x509.NameAttribute(x509.NameOID.COMMON_NAME, dn.cn))
|
||||
if dn.st:
|
||||
namen.append(x509.NameAttribute(x509.NameOID.STATE_OR_PROVINCE_NAME, dn.st))
|
||||
if dn.l:
|
||||
namen.append(x509.NameAttribute(x509.NameOID.LOCALITY_NAME, dn.l))
|
||||
if dn.o:
|
||||
namen.append(x509.NameAttribute(x509.NameOID.ORGANIZATION_NAME, dn.o))
|
||||
if dn.ou:
|
||||
namen.append(x509.NameAttribute(x509.NameOID.ORGANIZATIONAL_UNIT_NAME, dn.ou))
|
||||
if dn.c:
|
||||
namen.append(x509.NameAttribute(x509.NameOID.COUNTRY_NAME, dn.c))
|
||||
if dn.street:
|
||||
namen.append(x509.NameAttribute(x509.NameOID.STREET_ADDRESS, dn.street))
|
||||
return namen
|
||||
|
||||
def newca(self):
|
||||
privater = self.wrapper.gencert(self.arguments.länge)
|
||||
jetzt = datetime.datetime.now()
|
||||
privater.add_done_callback(print_wrp("Privater Schlüssel generiert"))
|
||||
subject = x509.Name(self.parsedn(self.arguments))
|
||||
zertifikat = self.wrapper.sign(
|
||||
subject=subject,
|
||||
issuer=subject,
|
||||
time_valid=datetime.timedelta(days=self.arguments.tage),
|
||||
public_key=privater.result().public_key(),
|
||||
privat_ca_key=privater.result()
|
||||
)
|
||||
passwort = self.frage("Passwort")
|
||||
if passwort:
|
||||
encryption = BestAvailableEncryption(passwort.encode())
|
||||
else:
|
||||
encryption = NoEncryption()
|
||||
self.db.insert_certificate(
|
||||
self.arguments.cn,
|
||||
hex(zertifikat.serial_number),
|
||||
zertifikat.public_bytes(Encoding.PEM),
|
||||
privater.result().private_bytes(encoding=Encoding.PEM, format=PrivateFormat.PKCS8, encryption_algorithm=encryption),
|
||||
True
|
||||
)
|
||||
|
||||
def request(self):
|
||||
erweiterungen = []
|
||||
if self.arguments.ca:
|
||||
erweiterungen.append(x509.BasicConstraints(True, self.arguments.ca))
|
||||
else:
|
||||
erweiterungen.append(x509.BasicConstraints(False, None))
|
||||
if self.arguments.san:
|
||||
alt = []
|
||||
for san in self.arguments.san:
|
||||
if ":" in san:
|
||||
alt.append(x509.UniformResourceIdentifier(san))
|
||||
elif "@" in san:
|
||||
alt.append(x509.RFC822Name(san))
|
||||
else:
|
||||
alt.append(x509.DNSName(san))
|
||||
erweiterungen.append(x509.SubjectAlternativeName(alt))
|
||||
ziele = []
|
||||
if self.arguments.server:
|
||||
ziele.append(x509.oid.ExtendedKeyUsageOID.SERVER_AUTH)
|
||||
if self.arguments.client:
|
||||
ziele.append(x509.oid.ExtendedKeyUsageOID.CLIENT_AUTH)
|
||||
if self.arguments.code:
|
||||
ziele.append(x509.oid.ExtendedKeyUsageOID.CODE_SIGNING)
|
||||
if self.arguments.email:
|
||||
ziele.append(x509.oid.ExtendedKeyUsageOID.EMAIL_PROTECTION)
|
||||
erweiterungen.append(x509.ExtendedKeyUsage(ziele))
|
||||
anfrage = self.wrapper.request(
|
||||
subject=x509.Name(self.parsedn(self.arguments)),
|
||||
erweiterungen=erweiterungen,
|
||||
certlänge=self.arguments.länge
|
||||
)
|
||||
passwort = self.frage("Passwort")
|
||||
if passwort:
|
||||
encryption = BestAvailableEncryption(passwort.encode())
|
||||
else:
|
||||
encryption = NoEncryption()
|
||||
self.db.insert_request(
|
||||
self.arguments.cn,
|
||||
anfrage.public_bytes(Encoding.PEM),
|
||||
privater.result().private_bytes(encoding=Encoding.PEM, format=PrivateFormat.PKCS8, encryption_algorithm=encryption),
|
||||
)
|
||||
self.connection.commit()
|
||||
|
||||
def sign(self):
|
||||
def delete_request(subject):
|
||||
self.cursor.execute("DELETE FROM requests WHERE commonname=?", (subject, ))
|
||||
self.cursor.execute("SELECT commonname, csr, privatkey FROM requests")
|
||||
for reihe in self.cursor.fetchall():
|
||||
try:
|
||||
anfrage = x509.load_pem_x509_csr(reihe["csr"], self.backend)
|
||||
if not anfrage.is_signature_valid:
|
||||
raise TypeError()
|
||||
except TypeError:
|
||||
delete_request(reihe["commonname"])
|
||||
continue
|
||||
print_info(anfrage)
|
||||
if not self.frage("Möchten Sie das Zertifikat signieren[01]" ,int):
|
||||
delete_request(reihe["commonname"])
|
||||
continue
|
||||
cas = []
|
||||
for row in self.cursor.execute("SELECT commonname, publickey, privatkey FROM certificates WHERE ca=1"):
|
||||
cas.append((row["commonname"], x509.load_pem_x509_certificate(row["publickey"], self.backend), row["privatkey"]))
|
||||
print("Wähle die CA:\n")
|
||||
for counter in range(1, len(cas)+1):
|
||||
print("{}: {}".format(counter, cas[counter-1][0]))
|
||||
while True:
|
||||
antwort = self.frage("CA", int)
|
||||
antwort -= 1
|
||||
if 0 <= antwort < len(cas):
|
||||
break
|
||||
try:
|
||||
privat = load_pem_private_key(cas[antwort][2], None, self.backend)
|
||||
except TypeError:
|
||||
while True:
|
||||
try:
|
||||
pw = self.frage("Passwort")
|
||||
privat = load_pem_private_key(cas[antwort][2], pw.encode("utf-8"), self.backend)
|
||||
except TypeError:
|
||||
print("Falsches Passwort")
|
||||
ca = cas[antwort][1]
|
||||
dn = cas[antwort][0]
|
||||
zertifikat = self.sign_cert(
|
||||
anfrage.subject,
|
||||
ca.subject,
|
||||
datetime.timedelta(days=self.frage("Laufzeit", int)),
|
||||
anfrage.public_key(),
|
||||
privat,
|
||||
[ext.value for ext in anfrage.extensions],
|
||||
ca
|
||||
)
|
||||
self.db.insert_certificate(
|
||||
reihe["commonname"],
|
||||
hex(zertifikat.serial_number),
|
||||
zertifikat.public_bytes(Encoding.PEM),
|
||||
reihe["privatkey"],
|
||||
dn,
|
||||
0
|
||||
)
|
||||
delete_request(reihe["commonname"])
|
||||
self.connection.commit()
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = parser_factory()
|
||||
argumente = parser.parse_args()
|
||||
print(argumente.aktion)
|
||||
datenbank = sqlite3.connect(argumente.db)
|
||||
initdb(datenbank.cursor())
|
||||
commandos = Commands(default_backend(), datenbank, argumente)
|
||||
if commandos.get(argumente.aktion):
|
||||
commandos.get(argumente.aktion)()
|
||||
else:
|
||||
parser.print_help()
|
In neuem Issue referenzieren