build individual x509 stores for each CRL

This commit is contained in:
dandds
2018-08-16 14:09:18 -04:00
committed by luis cielak
parent a72c8498a2
commit e9d6ee8102
7 changed files with 80 additions and 81 deletions

View File

@@ -16,7 +16,7 @@ from atst.routes.workspaces import bp as workspace_routes
from atst.routes.requests import requests_bp
from atst.routes.dev import bp as dev_routes
from atst.routes.errors import make_error_pages
from atst.domain.authnid.crl import Validator, CRLCache
from atst.domain.authnid.crl import CRLCache
from atst.domain.auth import apply_authentication

View File

@@ -1,17 +1,18 @@
from atst.domain.exceptions import UnauthenticatedError, NotFoundError
from atst.domain.users import Users
from .utils import parse_sdn, email_from_certificate
from .crl import Validator
class AuthenticationContext():
def __init__(self, crl_validator, auth_status, sdn, cert):
def __init__(self, crl_cache, auth_status, sdn, cert):
if None in locals().values():
raise UnauthenticatedError(
"Missing required authentication context components"
)
self.crl_validator = crl_validator
self.crl_cache = crl_cache
self.auth_status = auth_status
self.sdn = sdn
self.cert = cert.encode()
@@ -44,8 +45,9 @@ class AuthenticationContext():
return None
def _crl_check(self):
validator = Validator(self.crl_cache, self.cert)
if self.cert:
result = self.crl_validator.validate(self.cert)
result = validator.validate()
return result
else:

View File

@@ -56,28 +56,50 @@ class CRLCache():
# theoretically it can build a longer certificate chain
def _add_certificate_chain_to_store(self, store, issuer):
ca = self.certificate_authorities.get(issuer.der())
# i.e., it is the root CA
if issuer == ca.get_subject():
return store
store.add_cert(ca)
return self._add_certificate_chain_to_store(store, ca.get_issuer())
if issuer == ca.get_subject():
# i.e., it is the root CA and we are at the end of the chain
return store
else:
return self._add_certificate_chain_to_store(store, ca.get_issuer())
def get_store(self, cert):
return self._check_cache(cert.get_issuer().der())
def _check_cache(self, issuer):
if issuer in self.crl_cache:
filename, checksum = self.crl_cache[issuer]
if sha256_checksum(filename) != checksum:
issuer, store = self._build_store(filename)
self.x509_stores[issuer] = store
return store
else:
return self.x509_stores[issuer]
class Validator:
_PEM_RE = re.compile(
b"-----BEGIN CERTIFICATE-----\r?.+?\r?-----END CERTIFICATE-----\r?\n?",
re.DOTALL,
)
def __init__(self, root, crl_locations=[], base_store=crypto.X509Store, logger=None):
self.crl_locations = crl_locations
self.root = root
self.base_store = base_store
def __init__(self, cache, cert, logger=None):
self.cache = cache
self.cert = cert
self.logger = logger
self._reset()
def validate(self):
parsed = crypto.load_certificate(crypto.FILETYPE_PEM, self.cert)
store = self.cache.get_store(parsed)
context = crypto.X509StoreContext(store, parsed)
try:
context.verify_certificate()
return True
except crypto.X509StoreContextError as err:
self.log_error(
"Certificate revoked or errored. Error: {}. Args: {}".format(
type(err), err.args
)
)
return False
def _add_roots(self, roots):
with open(filename, "rb") as f:
@@ -161,26 +183,3 @@ class Validator:
return error.args == self.PRELOADED_CRL or error.args == self.PRELOADED_CERT
# Checks that the CRL currently in-memory is up-to-date via the checksum.
def refresh_cache(self, cert):
der = cert.get_issuer().der()
if der in self.cache:
filename, checksum = self.cache[der]
if sha256_checksum(filename) != checksum:
self._reset()
def validate(self, cert):
parsed = crypto.load_certificate(crypto.FILETYPE_PEM, cert)
self.refresh_cache(parsed)
context = crypto.X509StoreContext(self.store, parsed)
try:
context.verify_certificate()
return True
except crypto.X509StoreContextError as err:
self.log_error(
"Certificate revoked or errored. Error: {}. Args: {}".format(
type(err), err.args
)
)
return False

View File

@@ -32,7 +32,7 @@ def catch_all(path):
def _make_authentication_context():
return AuthenticationContext(
crl_validator=app.crl_validator,
crl_cache=app.crl_cache,
auth_status=request.environ.get("HTTP_X_SSL_CLIENT_VERIFY"),
sdn=request.environ.get("HTTP_X_SSL_CLIENT_S_DN"),
cert=request.environ.get("HTTP_X_SSL_CLIENT_CERT")