1
0
mirror of https://github.com/laurivosandi/certidude synced 2024-09-28 21:11:42 +00:00

Add OpenVPN bundle generation

This commit is contained in:
Lauri Võsandi 2017-01-25 11:34:08 +00:00
parent cca9d2ab2d
commit 1925207a6d
4 changed files with 56 additions and 6 deletions

View File

@ -12,6 +12,8 @@ KEYWORDS = (
(u"iPhone", u"iphone"), (u"iPhone", u"iphone"),
(u"iPad", u"ipad"), (u"iPad", u"ipad"),
(u"Ubuntu", u"ubuntu"), (u"Ubuntu", u"ubuntu"),
(u"Fedora", u"fedora"),
(u"Linux", u"linux"),
) )
class BundleResource(object): class BundleResource(object):
@ -29,8 +31,15 @@ class BundleResource(object):
hashlib.sha256(req.user_agent).hexdigest()[:8]) hashlib.sha256(req.user_agent).hexdigest()[:8])
logger.info(u"Signing bundle %s for %s", common_name, req.context.get("user")) logger.info(u"Signing bundle %s for %s", common_name, req.context.get("user"))
resp.set_header("Content-Type", "application/x-pkcs12") if config.BUNDLE_FORMAT == "p12":
resp.set_header("Content-Disposition", "attachment; filename=%s.p12" % common_name.encode("ascii")) resp.set_header("Content-Type", "application/x-pkcs12")
resp.body, cert = authority.generate_pkcs12_bundle(common_name, resp.set_header("Content-Disposition", "attachment; filename=%s.p12" % common_name.encode("ascii"))
owner=req.context.get("user")) resp.body, cert = authority.generate_pkcs12_bundle(common_name,
owner=req.context.get("user"))
elif config.BUNDLE_FORMAT == "ovpn":
resp.set_header("Content-Type", "application/x-openvpn")
resp.set_header("Content-Disposition", "attachment; filename=%s.ovpn" % common_name.encode("ascii"))
resp.body, cert = authority.generate_ovpn_bundle(common_name,
owner=req.context.get("user"))
else:
raise ValueError("Unknown bundle format %s" % config.BUNDLE_FORMAT)

View File

@ -14,6 +14,7 @@ from cryptography.hazmat.primitives import hashes, serialization
from certidude import config, push, mailer, const from certidude import config, push, mailer, const
from certidude.wrappers import Certificate, Request from certidude.wrappers import Certificate, Request
from certidude import errors from certidude import errors
from jinja2 import Template
RE_HOSTNAME = "^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])(@(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9]))?$" RE_HOSTNAME = "^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])(@(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9]))?$"
@ -21,7 +22,6 @@ RE_HOSTNAME = "^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z
# https://jamielinux.com/docs/openssl-certificate-authority/ # https://jamielinux.com/docs/openssl-certificate-authority/
# http://pycopia.googlecode.com/svn/trunk/net/pycopia/ssl/certs.py # http://pycopia.googlecode.com/svn/trunk/net/pycopia/ssl/certs.py
# Cache CA certificate # Cache CA certificate
certificate = Certificate(open(config.AUTHORITY_CERTIFICATE_PATH)) certificate = Certificate(open(config.AUTHORITY_CERTIFICATE_PATH))
@ -185,6 +185,39 @@ def delete_request(common_name):
requests.delete(config.PUSH_PUBLISH % request.fingerprint(), requests.delete(config.PUSH_PUBLISH % request.fingerprint(),
headers={"User-Agent": "Certidude API"}) headers={"User-Agent": "Certidude API"})
def generate_ovpn_bundle(common_name, owner=None):
# Construct private key
click.echo("Generating 4096-bit RSA key...")
key = rsa.generate_private_key(
public_exponent=65537,
key_size=4096,
backend=default_backend()
)
csr = x509.CertificateSigningRequestBuilder().subject_name(x509.Name([
x509.NameAttribute(k, v) for k, v in (
(NameOID.COMMON_NAME, common_name),
(NameOID.GIVEN_NAME, owner and owner.given_name),
(NameOID.SURNAME, owner and owner.surname),
) if v
]))
# Sign CSR
cert = sign(Request(
csr.sign(key, hashes.SHA512(), default_backend()).public_bytes(serialization.Encoding.PEM)), overwrite=True)
bundle = Template(open(config.OPENVPN_BUNDLE_TEMPLATE).read()).render(
ca = certificate.dump(),
key = key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.TraditionalOpenSSL,
encryption_algorithm=serialization.NoEncryption()
),
cert = cert.dump(),
crl=export_crl(),
)
return bundle, cert
def generate_pkcs12_bundle(common_name, key_size=4096, owner=None): def generate_pkcs12_bundle(common_name, key_size=4096, owner=None):
""" """

View File

@ -40,6 +40,9 @@ SIGNED_DIR = cp.get("authority", "signed dir")
REVOKED_DIR = cp.get("authority", "revoked dir") REVOKED_DIR = cp.get("authority", "revoked dir")
OUTBOX = cp.get("authority", "outbox") OUTBOX = cp.get("authority", "outbox")
BUNDLE_FORMAT = cp.get("authority", "bundle format")
OPENVPN_BUNDLE_TEMPLATE = cp.get("authority", "openvpn bundle template")
USER_CERTIFICATE_ENROLLMENT = { USER_CERTIFICATE_ENROLLMENT = {
"forbidden": False, "single allowed": True, "multiple allowed": True }[ "forbidden": False, "single allowed": True, "multiple allowed": True }[
cp.get("authority", "user certificate enrollment")] cp.get("authority", "user certificate enrollment")]

View File

@ -95,3 +95,8 @@ revoked dir = {{ directory }}/revoked/
expired dir = {{ directory }}/expired/ expired dir = {{ directory }}/expired/
outbox = {{ outbox }} outbox = {{ outbox }}
bundle format = p12
;bundle format = ovpn
openvpn bundle template = /etc/certidude/template.ovpn