Browse Source

Update certgen.

pull/1200/head
Prinz23 6 years ago
committed by JackDandy
parent
commit
6c9be73404
  1. 201
      lib/certgen.py
  2. 26
      sickbeard/helpers.py

201
lib/certgen.py

@ -1,82 +1,127 @@
# -*- coding: latin-1 -*- #!/usr/bin/env python
#
# Copyright (C) Martin Sjögren and AB Strakt 2001, All rights reserved
# Copyright (C) Jean-Paul Calderone 2008, All rights reserved
# This file is licenced under the GNU LESSER GENERAL PUBLIC LICENSE Version 2.1 or later (aka LGPL v2.1)
# Please see LGPL2.1.txt for more information
""" """
Certificate generation module. Adapted from the docs of cryptography
Creates a key and self-signed certificate for local use
""" """
from OpenSSL import crypto import datetime
import time import os
import socket
TYPE_RSA = crypto.TYPE_RSA
TYPE_DSA = crypto.TYPE_DSA # noinspection PyPackageRequirements
from cryptography.hazmat.backends import default_backend
serial = int(time.time()) # noinspection PyPackageRequirements
from cryptography.hazmat.primitives import hashes, serialization
# noinspection PyPackageRequirements
def createKeyPair(type, bits): from cryptography.hazmat.primitives.asymmetric import rsa
""" # noinspection PyPackageRequirements
Create a public/private key pair. from cryptography import x509
# noinspection PyPackageRequirements
Arguments: type - Key type, must be one of TYPE_RSA and TYPE_DSA from cryptography.x509.oid import NameOID
bits - Number of bits to use in the key
Returns: The public/private key pair in a PKey object from six import PY2, text_type
"""
pkey = crypto.PKey()
pkey.generate_key(type, bits) def localipv4():
return pkey try:
s_ipv4 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
def createCertRequest(pkey, digest="md5", **name): s_ipv4.connect(('1.2.3.4', 80)) # Option: use 100.64.1.1 (IANA-Reserved IPv4 Prefix for Shared Address Space)
""" ipv4 = s_ipv4.getsockname()[0]
Create a certificate request. s_ipv4.close()
except (BaseException, Exception):
Arguments: pkey - The key to associate with the request ipv4 = None
digest - Digestion method to use for signing, default is md5 return ipv4
**name - The name of the subject of the request, possible
arguments are:
C - Country name # Ported from cryptography/utils.py
ST - State or province name def int_from_bytes(data, byteorder, signed=False):
L - Locality name assert 'big' == byteorder
O - Organization name assert not signed
OU - Organizational unit name
CN - Common name if not PY2:
emailAddress - E-mail address import binascii
Returns: The certificate request in an X509Req object return int(binascii.hexlify(data), 16)
"""
req = crypto.X509Req() # call bytes() on data to allow the use of bytearrays
subj = req.get_subject() # noinspection PyUnresolvedReferences
return int(bytes(data).encode('hex'), 16)
for (key,value) in name.items():
setattr(subj, key, value)
# Ported from cryptography/x509/base.py
req.set_pubkey(pkey) def random_serial_number():
req.sign(pkey, digest) return int_from_bytes(os.urandom(20), 'big') >> 1
return req
def createCertificate(req, (issuerCert, issuerKey), serial, (notBefore, notAfter), digest="md5"): # Ported from cryptography docs/x509/tutorial.rst (set with no encryption)
""" def generate_key(key_size=4096, output_file='server.key'):
Generate a certificate given a certificate request. # Generate our key
private_key = rsa.generate_private_key(
Arguments: req - Certificate reqeust to use public_exponent=65537,
issuerCert - The certificate of the issuer key_size=key_size,
issuerKey - The private key of the issuer backend=default_backend()
serial - Serial number for the certificate )
notBefore - Timestamp (relative to now) when the certificate
starts being valid # Write our key to disk for safe keeping
notAfter - Timestamp (relative to now) when the certificate with open(output_file, 'wb') as f:
stops being valid f.write(private_key.private_bytes(
digest - Digest method to use for signing, default is md5 encoding=serialization.Encoding.PEM,
Returns: The signed certificate in an X509 object format=serialization.PrivateFormat.TraditionalOpenSSL,
""" encryption_algorithm=serialization.NoEncryption()
cert = crypto.X509() ))
cert.set_serial_number(serial)
cert.gmtime_adj_notBefore(notBefore) return private_key
cert.gmtime_adj_notAfter(notAfter)
cert.set_issuer(issuerCert.get_subject())
cert.set_subject(req.get_subject()) # Ported from cryptography docs/x509/tutorial.rst
cert.set_pubkey(req.get_pubkey()) def generate_local_cert(private_key, days_valid=3650, output_file='server.crt', loc_name=None, org_name=None):
cert.sign(issuerKey, digest)
def_name = u'SickGear'
# Various details about who we are. For a self-signed certificate the
# subject and issuer are always the same.
subject = issuer = x509.Name([
x509.NameAttribute(NameOID.LOCALITY_NAME, loc_name or def_name),
x509.NameAttribute(NameOID.ORGANIZATION_NAME, org_name or def_name)
])
# build Subject Alternate Names (aka SAN) list
# First the host names, add with x509.DNSName():
san_list = [x509.DNSName(u'localhost')]
try:
thishostname = text_type(socket.gethostname())
san_list.append(x509.DNSName(thishostname))
except (BaseException, Exception):
pass
# Then the host IP addresses, add with x509.IPAddress()
# Inside a try-except, just to be sure
try:
# noinspection PyCompatibility
from ipaddress import IPv4Address, IPv6Address
san_list.append(x509.IPAddress(IPv4Address(u'127.0.0.1')))
san_list.append(x509.IPAddress(IPv6Address(u'::1')))
# append local v4 ip
mylocalipv4 = localipv4()
if mylocalipv4:
san_list.append(x509.IPAddress(IPv4Address(u'' + mylocalipv4)))
except (ImportError, Exception):
pass
cert = x509.CertificateBuilder() \
.subject_name(subject) \
.issuer_name(issuer) \
.public_key(private_key.public_key()) \
.not_valid_before(datetime.datetime.utcnow()) \
.not_valid_after(datetime.datetime.utcnow() + datetime.timedelta(days=days_valid)) \
.serial_number(random_serial_number()) \
.add_extension(x509.SubjectAlternativeName(san_list), critical=True) \
.sign(private_key, hashes.SHA256(), default_backend())
# Write the certificate out to disk.
with open(output_file, 'wb') as f:
f.write(cert.public_bytes(serialization.Encoding.PEM))
return cert return cert

26
sickbeard/helpers.py

@ -675,33 +675,15 @@ def create_https_certificates(ssl_cert, ssl_key):
""" """
Create self-signed HTTPS certificares and store in paths 'ssl_cert' and 'ssl_key' Create self-signed HTTPS certificares and store in paths 'ssl_cert' and 'ssl_key'
""" """
try:
from OpenSSL import crypto
from lib.certgen import createKeyPair, createCertRequest, createCertificate, TYPE_RSA, serial
except (StandardError, Exception):
logger.log(u"pyopenssl module missing, please install for https access", logger.WARNING)
return False
# Create the CA Certificate
cakey = createKeyPair(TYPE_RSA, 4096)
careq = createCertRequest(cakey, CN='Certificate Authority')
cacert = createCertificate(careq, (careq, cakey), serial, (0, 60 * 60 * 24 * 365 * 10)) # ten years
pkey = createKeyPair(TYPE_RSA, 4096)
req = createCertRequest(pkey, CN='SickGear')
cert = createCertificate(req, (cacert, cakey), serial, (0, 60 * 60 * 24 * 365 * 10)) # ten years
# Save the key and certificate to disk
try: try:
with open(ssl_key, 'w') as file_hd: from lib.certgen import generate_key, generate_local_cert
file_hd.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, pkey))
with open(ssl_cert, 'w') as file_hd:
file_hd.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert))
except (StandardError, Exception): except (StandardError, Exception):
logger.log(u"Error creating SSL key and certificate", logger.ERROR)
return False return False
return True private_key = generate_key(key_size=4096, output_file=ssl_key)
cert = generate_local_cert(private_key, days_valid=3650, output_file=ssl_cert)
return bool(cert)
if __name__ == '__main__': if __name__ == '__main__':

Loading…
Cancel
Save