Add key curve hash to bootstrap, code style fixes
This commit is contained in:
parent
31d4dad2be
commit
443c168cbd
@ -1,5 +1,4 @@
|
|||||||
import hashlib
|
import hashlib
|
||||||
import logging
|
|
||||||
from pinecrypt.server import authority, const, config
|
from pinecrypt.server import authority, const, config
|
||||||
from pinecrypt.server.common import cert_to_dn
|
from pinecrypt.server.common import cert_to_dn
|
||||||
from pinecrypt.server.decorators import serialize
|
from pinecrypt.server.decorators import serialize
|
||||||
@ -7,6 +6,7 @@ from pinecrypt.server.mongolog import LogHandler
|
|||||||
|
|
||||||
logger = LogHandler()
|
logger = LogHandler()
|
||||||
|
|
||||||
|
|
||||||
class BootstrapResource(object):
|
class BootstrapResource(object):
|
||||||
@serialize
|
@serialize
|
||||||
def on_get(self, req, resp):
|
def on_get(self, req, resp):
|
||||||
@ -31,6 +31,9 @@ class BootstrapResource(object):
|
|||||||
esp=config.get("Globals", "STRONGSWAN_ESP")["value"],
|
esp=config.get("Globals", "STRONGSWAN_ESP")["value"],
|
||||||
),
|
),
|
||||||
certificate=dict(
|
certificate=dict(
|
||||||
|
key_size=const.KEY_SIZE,
|
||||||
|
curve=const.CURVE_NAME,
|
||||||
|
hash_algorithm=const.CERTIFICATE_HASH_ALGORITHM,
|
||||||
algorithm=authority.public_key.algorithm,
|
algorithm=authority.public_key.algorithm,
|
||||||
common_name=authority.certificate.subject.native["common_name"],
|
common_name=authority.certificate.subject.native["common_name"],
|
||||||
distinguished_name=cert_to_dn(authority.certificate),
|
distinguished_name=cert_to_dn(authority.certificate),
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import click
|
import click
|
||||||
import logging
|
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import socket
|
import socket
|
||||||
@ -39,15 +38,15 @@ def self_enroll(skip_notify=False):
|
|||||||
cert, cert_doc, pem_buf = get_signed(common_name=common_name, namespace=const.AUTHORITY_NAMESPACE)
|
cert, cert_doc, pem_buf = get_signed(common_name=common_name, namespace=const.AUTHORITY_NAMESPACE)
|
||||||
self_public_key = asymmetric.load_public_key(cert["tbs_certificate"]["subject_public_key_info"])
|
self_public_key = asymmetric.load_public_key(cert["tbs_certificate"]["subject_public_key_info"])
|
||||||
private_key = asymmetric.load_private_key(const.SELF_KEY_PATH)
|
private_key = asymmetric.load_private_key(const.SELF_KEY_PATH)
|
||||||
except (NameError, FileNotFoundError, errors.CertificateDoesNotExist) as error: # certificate or private key not found
|
except (NameError, FileNotFoundError, errors.CertificateDoesNotExist): # certificate or private key not found
|
||||||
click.echo("Generating private key for frontend: %s" % const.SELF_KEY_PATH)
|
click.echo("Generating private key for frontend: %s" % const.SELF_KEY_PATH)
|
||||||
with open(const.SELF_KEY_PATH, 'wb') as fh:
|
with open(const.SELF_KEY_PATH, "wb") as fh:
|
||||||
if public_key.algorithm == "ec":
|
if public_key.algorithm == "ec":
|
||||||
self_public_key, private_key = asymmetric.generate_pair("ec", curve=public_key.curve)
|
self_public_key, private_key = asymmetric.generate_pair("ec", curve=public_key.curve)
|
||||||
elif public_key.algorithm == "rsa":
|
elif public_key.algorithm == "rsa":
|
||||||
self_public_key, private_key = asymmetric.generate_pair("rsa", bit_size=public_key.bit_size)
|
self_public_key, private_key = asymmetric.generate_pair("rsa", bit_size=public_key.bit_size)
|
||||||
else:
|
else:
|
||||||
raise NotImplemented("CA certificate public key algorithm %s not supported" % public_key.algorithm)
|
raise NotImplementedError("CA certificate public key algorithm %s not supported" % public_key.algorithm)
|
||||||
fh.write(asymmetric.dump_private_key(private_key, None))
|
fh.write(asymmetric.dump_private_key(private_key, None))
|
||||||
else:
|
else:
|
||||||
now = datetime.utcnow().replace(tzinfo=pytz.UTC)
|
now = datetime.utcnow().replace(tzinfo=pytz.UTC)
|
||||||
@ -55,8 +54,8 @@ def self_enroll(skip_notify=False):
|
|||||||
click.echo("Self certificate still valid, delete to self-enroll again")
|
click.echo("Self certificate still valid, delete to self-enroll again")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
builder = CSRBuilder({"common_name": common_name}, self_public_key)
|
builder = CSRBuilder({"common_name": common_name}, self_public_key)
|
||||||
|
builder.hash_algo = const.CERTIFICATE_HASH_ALGORITHM
|
||||||
request = builder.build(private_key)
|
request = builder.build(private_key)
|
||||||
|
|
||||||
now = datetime.utcnow().replace(tzinfo=pytz.UTC)
|
now = datetime.utcnow().replace(tzinfo=pytz.UTC)
|
||||||
@ -74,8 +73,9 @@ def self_enroll(skip_notify=False):
|
|||||||
"$set": d,
|
"$set": d,
|
||||||
"$setOnInsert": {
|
"$setOnInsert": {
|
||||||
"created": now,
|
"created": now,
|
||||||
"ip": [],
|
"ip": []
|
||||||
}},
|
}
|
||||||
|
},
|
||||||
upsert=True,
|
upsert=True,
|
||||||
return_document=db.return_new)
|
return_document=db.return_new)
|
||||||
|
|
||||||
@ -98,6 +98,7 @@ def get_common_name_id(cn):
|
|||||||
|
|
||||||
return str(doc["_id"])
|
return str(doc["_id"])
|
||||||
|
|
||||||
|
|
||||||
def list_revoked(limit=0):
|
def list_revoked(limit=0):
|
||||||
# TODO: sort recent to oldest
|
# TODO: sort recent to oldest
|
||||||
for cert_revoked_doc in db.certificates.find({"status": "revoked"}):
|
for cert_revoked_doc in db.certificates.find({"status": "revoked"}):
|
||||||
@ -108,6 +109,7 @@ def list_revoked(limit=0):
|
|||||||
if limit <= 0:
|
if limit <= 0:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
# TODO: it should be possible to regex search common_name directly from mongodb
|
# TODO: it should be possible to regex search common_name directly from mongodb
|
||||||
def list_signed(common_name=None):
|
def list_signed(common_name=None):
|
||||||
for cert_doc in db.certificates.find({"status": "signed"}):
|
for cert_doc in db.certificates.find({"status": "signed"}):
|
||||||
@ -121,11 +123,13 @@ def list_signed(common_name=None):
|
|||||||
cert = x509.Certificate.load(cert_doc["cert_buf"])
|
cert = x509.Certificate.load(cert_doc["cert_buf"])
|
||||||
yield cert_doc, cert
|
yield cert_doc, cert
|
||||||
|
|
||||||
|
|
||||||
def list_requests():
|
def list_requests():
|
||||||
for request in db.certificates.find({"status": "csr"}):
|
for request in db.certificates.find({"status": "csr"}):
|
||||||
csr = CertificationRequest.load(request["request_buf"])
|
csr = CertificationRequest.load(request["request_buf"])
|
||||||
yield csr, request, "." in request["common_name"]
|
yield csr, request, "." in request["common_name"]
|
||||||
|
|
||||||
|
|
||||||
def list_replicas():
|
def list_replicas():
|
||||||
"""
|
"""
|
||||||
Return list of Mongo objects referring to all active replicas
|
Return list of Mongo objects referring to all active replicas
|
||||||
@ -133,12 +137,14 @@ def list_replicas():
|
|||||||
for doc in db.certificates.find({"status": "signed", "profile.ou": "Gateway"}):
|
for doc in db.certificates.find({"status": "signed", "profile.ou": "Gateway"}):
|
||||||
yield doc
|
yield doc
|
||||||
|
|
||||||
|
|
||||||
def get_ca_cert():
|
def get_ca_cert():
|
||||||
fh = open(const.AUTHORITY_CERTIFICATE_PATH, "rb")
|
fh = open(const.AUTHORITY_CERTIFICATE_PATH, "rb")
|
||||||
server_certificate = asymmetric.load_certificate(fh.read())
|
server_certificate = asymmetric.load_certificate(fh.read())
|
||||||
fh.close()
|
fh.close()
|
||||||
return server_certificate
|
return server_certificate
|
||||||
|
|
||||||
|
|
||||||
def get_request(id):
|
def get_request(id):
|
||||||
if not id:
|
if not id:
|
||||||
raise ValueError("Invalid id parameter %s" % id)
|
raise ValueError("Invalid id parameter %s" % id)
|
||||||
@ -151,6 +157,7 @@ def get_request(id):
|
|||||||
csr = CertificationRequest.load(csr_doc["request_buf"])
|
csr = CertificationRequest.load(csr_doc["request_buf"])
|
||||||
return csr, csr_doc, pem_armor_csr(csr)
|
return csr, csr_doc, pem_armor_csr(csr)
|
||||||
|
|
||||||
|
|
||||||
def get_by_serial(serial):
|
def get_by_serial(serial):
|
||||||
serial_string = "%x" % serial
|
serial_string = "%x" % serial
|
||||||
query = {"serial_number": serial_string}
|
query = {"serial_number": serial_string}
|
||||||
@ -163,6 +170,7 @@ def get_by_serial(serial):
|
|||||||
cert = x509.Certificate.load(cert_doc["cert_buf"])
|
cert = x509.Certificate.load(cert_doc["cert_buf"])
|
||||||
return cert_doc, cert
|
return cert_doc, cert
|
||||||
|
|
||||||
|
|
||||||
def get_signed(mongo_id=False, common_name=False, namespace=const.AUTHORITY_NAMESPACE):
|
def get_signed(mongo_id=False, common_name=False, namespace=const.AUTHORITY_NAMESPACE):
|
||||||
|
|
||||||
if mongo_id:
|
if mongo_id:
|
||||||
@ -221,7 +229,6 @@ def store_request(buf, overwrite=False, address="", user="", namespace=const.MAC
|
|||||||
if not re.match(const.RE_COMMON_NAME, common_name):
|
if not re.match(const.RE_COMMON_NAME, common_name):
|
||||||
raise ValueError("Invalid common name %s" % repr(common_name))
|
raise ValueError("Invalid common name %s" % repr(common_name))
|
||||||
|
|
||||||
|
|
||||||
query = {"common_name": common_name, "status": "csr"}
|
query = {"common_name": common_name, "status": "csr"}
|
||||||
doc = db.certificates.find_one(query)
|
doc = db.certificates.find_one(query)
|
||||||
d = {}
|
d = {}
|
||||||
@ -267,6 +274,7 @@ def store_request(buf, overwrite=False, address="", user="", namespace=const.MAC
|
|||||||
|
|
||||||
return doc
|
return doc
|
||||||
|
|
||||||
|
|
||||||
def revoke(mongo_id, reason, user="root"):
|
def revoke(mongo_id, reason, user="root"):
|
||||||
"""
|
"""
|
||||||
Revoke valid certificate
|
Revoke valid certificate
|
||||||
@ -288,7 +296,7 @@ def revoke(mongo_id, reason, user="root"):
|
|||||||
else:
|
else:
|
||||||
raise ValueError("No common name or Id specified")
|
raise ValueError("No common name or Id specified")
|
||||||
|
|
||||||
prev = db.certificates.find_one(query)
|
# prev = db.certificates.find_one(query)
|
||||||
newValue = {"$set": {"status": "revoked", "revocation_reason": reason, "revoked": datetime.utcnow().replace(tzinfo=pytz.UTC)}}
|
newValue = {"$set": {"status": "revoked", "revocation_reason": reason, "revoked": datetime.utcnow().replace(tzinfo=pytz.UTC)}}
|
||||||
db.certificates.find_one_and_update(query, newValue)
|
db.certificates.find_one_and_update(query, newValue)
|
||||||
|
|
||||||
@ -299,6 +307,7 @@ def revoke(mongo_id, reason, user="root"):
|
|||||||
serial_hex="%x" % cert.serial_number,
|
serial_hex="%x" % cert.serial_number,
|
||||||
common_name=common_name)
|
common_name=common_name)
|
||||||
|
|
||||||
|
|
||||||
def export_crl(pem=True):
|
def export_crl(pem=True):
|
||||||
builder = CertificateListBuilder(
|
builder = CertificateListBuilder(
|
||||||
const.AUTHORITY_CRL_URL,
|
const.AUTHORITY_CRL_URL,
|
||||||
@ -334,7 +343,8 @@ def delete_request(id, user="root"):
|
|||||||
id))
|
id))
|
||||||
raise errors.RequestDoesNotExist
|
raise errors.RequestDoesNotExist
|
||||||
|
|
||||||
res = db.certificates.delete_one(query)
|
# TODO return if was success or failure
|
||||||
|
db.certificates.delete_one(query)
|
||||||
|
|
||||||
logger.info("Rejected signing request %s %s by %s" % (doc["common_name"],
|
logger.info("Rejected signing request %s %s by %s" % (doc["common_name"],
|
||||||
id, user))
|
id, user))
|
||||||
@ -349,7 +359,6 @@ def sign(profile, skip_notify=False, overwrite=False, signer=None, namespace=con
|
|||||||
else:
|
else:
|
||||||
raise ValueError("ID missing, what CSR to sign")
|
raise ValueError("ID missing, what CSR to sign")
|
||||||
|
|
||||||
|
|
||||||
assert isinstance(csr, CertificationRequest)
|
assert isinstance(csr, CertificationRequest)
|
||||||
|
|
||||||
csr_pubkey = asymmetric.load_public_key(csr["certification_request_info"]["subject_pk_info"])
|
csr_pubkey = asymmetric.load_public_key(csr["certification_request_info"]["subject_pk_info"])
|
||||||
@ -382,6 +391,9 @@ def sign(profile, skip_notify=False, overwrite=False, signer=None, namespace=con
|
|||||||
ou=profile["ou"]), csr_pubkey)
|
ou=profile["ou"]), csr_pubkey)
|
||||||
builder.serial_number = generate_serial()
|
builder.serial_number = generate_serial()
|
||||||
|
|
||||||
|
if csr["signature_algorithm"].hash_algo == const.CERTIFICATE_HASH_ALGORITHM:
|
||||||
|
builder.hash_algo = const.CERTIFICATE_HASH_ALGORITHM
|
||||||
|
|
||||||
now = datetime.utcnow().replace(tzinfo=pytz.UTC)
|
now = datetime.utcnow().replace(tzinfo=pytz.UTC)
|
||||||
builder.begin_date = now - const.CLOCK_SKEW_TOLERANCE
|
builder.begin_date = now - const.CLOCK_SKEW_TOLERANCE
|
||||||
builder.end_date = now + timedelta(days=profile["lifetime"])
|
builder.end_date = now + timedelta(days=profile["lifetime"])
|
||||||
|
@ -10,7 +10,6 @@ else:
|
|||||||
|
|
||||||
import falcon
|
import falcon
|
||||||
import click
|
import click
|
||||||
import logging
|
|
||||||
import os
|
import os
|
||||||
import pymongo
|
import pymongo
|
||||||
import signal
|
import signal
|
||||||
@ -27,14 +26,12 @@ from pinecrypt.server import const, mongolog, mailer, db
|
|||||||
from pinecrypt.server.middleware import NormalizeMiddleware, PrometheusEndpoint
|
from pinecrypt.server.middleware import NormalizeMiddleware, PrometheusEndpoint
|
||||||
from pinecrypt.server.common import cn_to_dn, generate_serial
|
from pinecrypt.server.common import cn_to_dn, generate_serial
|
||||||
from pinecrypt.server.mongolog import LogHandler
|
from pinecrypt.server.mongolog import LogHandler
|
||||||
#from pinecrypt.server.logger import CertidudeLogger
|
|
||||||
from time import sleep
|
from time import sleep
|
||||||
from wsgiref.simple_server import make_server
|
from wsgiref.simple_server import make_server
|
||||||
|
|
||||||
#logger = logging.getLogger(__name__)
|
|
||||||
#logger = CertidudeLogger()
|
|
||||||
logger = LogHandler()
|
logger = LogHandler()
|
||||||
|
|
||||||
|
|
||||||
def graceful_exit(signal_number, stack_frame):
|
def graceful_exit(signal_number, stack_frame):
|
||||||
print("Received signal %d, exiting now" % signal_number)
|
print("Received signal %d, exiting now" % signal_number)
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
@ -236,7 +233,6 @@ def pinecone_provision():
|
|||||||
config = {"_id": "rs0", "members": [
|
config = {"_id": "rs0", "members": [
|
||||||
{"_id": index, "host": "%s:%s" % (ip_port[0], ip_port[1])} for index, ip_port in enumerate(mongo_uri["nodelist"])]}
|
{"_id": index, "host": "%s:%s" % (ip_port[0], ip_port[1])} for index, ip_port in enumerate(mongo_uri["nodelist"])]}
|
||||||
|
|
||||||
|
|
||||||
# config = {"_id":"rs0", "members": [
|
# config = {"_id":"rs0", "members": [
|
||||||
# {"_id": 0, "host": "127.0.0.1:27017"}]}
|
# {"_id": 0, "host": "127.0.0.1:27017"}]}
|
||||||
print("Provisioning MongoDB replicaset: %s" % repr(config))
|
print("Provisioning MongoDB replicaset: %s" % repr(config))
|
||||||
@ -263,6 +259,7 @@ def pinecone_provision():
|
|||||||
|
|
||||||
# https://technet.microsoft.com/en-us/library/aa998840(v=exchg.141).aspx
|
# https://technet.microsoft.com/en-us/library/aa998840(v=exchg.141).aspx
|
||||||
builder = CertificateBuilder(distinguished_name, public_key)
|
builder = CertificateBuilder(distinguished_name, public_key)
|
||||||
|
builder.hash_algo = const.CERTIFICATE_HASH_ALGORITHM
|
||||||
builder.self_signed = True
|
builder.self_signed = True
|
||||||
builder.ca = True
|
builder.ca = True
|
||||||
builder.serial_number = generate_serial()
|
builder.serial_number = generate_serial()
|
||||||
|
@ -35,8 +35,13 @@ REPLICAS = [j for j in os.getenv("REPLICAS", "").split(",") if j]
|
|||||||
if not MONGO_URI:
|
if not MONGO_URI:
|
||||||
MONGO_URI = "mongodb://127.0.0.1:27017/default?replicaSet=rs0"
|
MONGO_URI = "mongodb://127.0.0.1:27017/default?replicaSet=rs0"
|
||||||
|
|
||||||
KEY_SIZE = 4096
|
# Are set later, based on key type
|
||||||
CURVE_NAME = "secp384r1"
|
KEY_SIZE = None
|
||||||
|
CURVE_NAME = None
|
||||||
|
|
||||||
|
# python CSRbuilder supports right now sha1, sha256 sha512
|
||||||
|
# CERTIFICATE_HASH_ALGORITHM = 'sha111'
|
||||||
|
CERTIFICATE_HASH_ALGORITHM = "sha512"
|
||||||
|
|
||||||
# Kerberos-like clock skew tolerance
|
# Kerberos-like clock skew tolerance
|
||||||
CLOCK_SKEW_TOLERANCE = timedelta(minutes=5)
|
CLOCK_SKEW_TOLERANCE = timedelta(minutes=5)
|
||||||
@ -100,6 +105,12 @@ AUTHORITY_OCSP_URL = "http://%s/api/ocsp/" % AUTHORITY_NAMESPACE
|
|||||||
AUTHORITY_OCSP_DISABLED = os.getenv("AUTHORITY_OCSP_DISABLED", False)
|
AUTHORITY_OCSP_DISABLED = os.getenv("AUTHORITY_OCSP_DISABLED", False)
|
||||||
AUTHORITY_KEYTYPE = getenv_in("AUTHORITY_KEYTYPE", "rsa", "ec")
|
AUTHORITY_KEYTYPE = getenv_in("AUTHORITY_KEYTYPE", "rsa", "ec")
|
||||||
|
|
||||||
|
if AUTHORITY_KEYTYPE == "rsa":
|
||||||
|
KEY_SIZE = 4096
|
||||||
|
|
||||||
|
if AUTHORITY_KEYTYPE == "ec":
|
||||||
|
CURVE_NAME = "secp384r1"
|
||||||
|
|
||||||
# Tokens
|
# Tokens
|
||||||
TOKEN_URL = "https://%(authority_name)s/#action=enroll&title=dev.lan&token=%(token)s&subject=%(subject_username)s&protocols=%(protocols)s"
|
TOKEN_URL = "https://%(authority_name)s/#action=enroll&title=dev.lan&token=%(token)s&subject=%(subject_username)s&protocols=%(protocols)s"
|
||||||
TOKEN_LIFETIME = 3600 * 24
|
TOKEN_LIFETIME = 3600 * 24
|
||||||
|
Loading…
Reference in New Issue
Block a user