Merge pull request #3081 from charhate/pub_issuer
Cert validity should not exceed 397 days for publicly trusted issuers
This commit is contained in:
commit
14b73b73cf
|
@ -66,7 +66,7 @@ Basic Configuration
|
|||
|
||||
|
||||
.. data:: SQLALCHEMY_POOL_SIZE
|
||||
:noindex:
|
||||
:noindex:
|
||||
|
||||
The default connection pool size is 5 for sqlalchemy managed connections. Depending on the number of Lemur instances,
|
||||
please specify per instance connection pool size. Below is an example to set connection pool size to 10.
|
||||
|
@ -80,7 +80,7 @@ Basic Configuration
|
|||
This is an optional setting but important to review and set for optimal database connection usage and for overall database performance.
|
||||
|
||||
.. data:: SQLALCHEMY_MAX_OVERFLOW
|
||||
:noindex:
|
||||
:noindex:
|
||||
|
||||
This setting allows to create connections in addition to specified number of connections in pool size. By default, sqlalchemy
|
||||
allows 10 connections to create in addition to the pool size. This is also an optional setting. If `SQLALCHEMY_POOL_SIZE` and
|
||||
|
@ -155,6 +155,22 @@ Specifying the `SQLALCHEMY_MAX_OVERFLOW` to 0 will enforce limit to not create c
|
|||
|
||||
LEMUR_ENCRYPTION_KEYS = ['1YeftooSbxCiX2zo8m1lXtpvQjy27smZcUUaGmffhMY=', 'LAfQt6yrkLqOK5lwpvQcT4jf2zdeTQJV1uYeh9coT5s=']
|
||||
|
||||
.. data:: PUBLIC_CA_AUTHORITY_NAMES
|
||||
:noindex:
|
||||
A list of public issuers which would be checked against to determine whether limit of max validity of 397 days
|
||||
should be applied to the certificate. Configure public CA authority names in this list to enforce validity check.
|
||||
This is an optional setting. Using this will allow the sanity check as mentioned. The name check is a case-insensitive
|
||||
string comparision.
|
||||
|
||||
.. data:: PUBLIC_CA_MAX_VALIDITY_DAYS
|
||||
:noindex:
|
||||
Use this config to override the limit of 397 days of validity for certificates issued by public issuers configured
|
||||
using PUBLIC_CA_AUTHORITY_NAMES. Below example overrides the default validity of 397 days and sets it to 365 days.
|
||||
|
||||
::
|
||||
|
||||
PUBLIC_CA_MAX_VALIDITY_DAYS = 365
|
||||
|
||||
|
||||
.. data:: DEBUG_DUMP
|
||||
:noindex:
|
||||
|
@ -729,16 +745,16 @@ The following configuration properties are required to use the Digicert issuer p
|
|||
This is the root to be used for your CA chain
|
||||
|
||||
|
||||
.. data:: DIGICERT_DEFAULT_VALIDITY
|
||||
.. data:: DIGICERT_DEFAULT_VALIDITY_DAYS
|
||||
:noindex:
|
||||
|
||||
This is the default validity (in years), if no end date is specified. (Default: 1)
|
||||
This is the default validity (in days), if no end date is specified. (Default: 397)
|
||||
|
||||
|
||||
.. data:: DIGICERT_MAX_VALIDITY
|
||||
.. data:: DIGICERT_MAX_VALIDITY_DAYS
|
||||
:noindex:
|
||||
|
||||
This is the maximum validity (in years). (Default: value of DIGICERT_DEFAULT_VALIDITY)
|
||||
This is the maximum validity (in days). (Default: value of DIGICERT_DEFAULT_VALIDITY_DAYS)
|
||||
|
||||
|
||||
.. data:: DIGICERT_PRIVATE
|
||||
|
|
|
@ -152,6 +152,18 @@ def dates(data):
|
|||
data["authority"].authority_certificate.not_after
|
||||
)
|
||||
)
|
||||
# Allow no more than PUBLIC_CA_MAX_VALIDITY_DAYS (Default: 397) days of validity
|
||||
# for certs issued by public CA
|
||||
# The list of public issuers can be managed through a config named PUBLIC_CA
|
||||
public_CA = current_app.config.get("PUBLIC_CA_AUTHORITY_NAMES", [])
|
||||
if data["authority"].name.lower() in [ca.lower() for ca in public_CA]:
|
||||
max_validity_days = current_app.config.get("PUBLIC_CA_MAX_VALIDITY_DAYS", 397)
|
||||
if (
|
||||
(data.get("validity_end").date() - data.get("validity_start").date()).days
|
||||
> max_validity_days
|
||||
):
|
||||
raise ValidationError("Certificate cannot be valid for more than " +
|
||||
str(max_validity_days) + " days")
|
||||
|
||||
return data
|
||||
|
||||
|
|
|
@ -61,18 +61,16 @@ def signature_hash(signing_algorithm):
|
|||
|
||||
|
||||
def determine_validity_years(years):
|
||||
"""Given an end date determine how many years into the future that date is.
|
||||
:param years:
|
||||
:return: validity in years
|
||||
"""
|
||||
default_years = current_app.config.get("DIGICERT_DEFAULT_VALIDITY", 1)
|
||||
max_years = current_app.config.get("DIGICERT_MAX_VALIDITY", default_years)
|
||||
Considering maximum allowed certificate validity period of 397 days, this method should not return
|
||||
more than 1 year of validity. Thus changing it to always return 1.
|
||||
Lemur will change this method in future to handle validity in months (determine_validity_months)
|
||||
instead of years. This will allow flexibility to handle short-lived certificates.
|
||||
|
||||
if years > max_years:
|
||||
return max_years
|
||||
if years not in [1, 2, 3]:
|
||||
return default_years
|
||||
return years
|
||||
:param years:
|
||||
:return: 1
|
||||
"""
|
||||
return 1
|
||||
|
||||
|
||||
def determine_end_date(end_date):
|
||||
|
@ -82,11 +80,11 @@ def determine_end_date(end_date):
|
|||
:param end_date:
|
||||
:return: validity_end
|
||||
"""
|
||||
default_years = current_app.config.get("DIGICERT_DEFAULT_VALIDITY", 1)
|
||||
max_validity_end = arrow.utcnow().shift(years=current_app.config.get("DIGICERT_MAX_VALIDITY", default_years))
|
||||
default_days = current_app.config.get("DIGICERT_DEFAULT_VALIDITY_DAYS", 397)
|
||||
max_validity_end = arrow.utcnow().shift(days=current_app.config.get("DIGICERT_MAX_VALIDITY_DAYS", default_days))
|
||||
|
||||
if not end_date:
|
||||
end_date = arrow.utcnow().shift(years=default_years)
|
||||
end_date = arrow.utcnow().shift(days=default_days)
|
||||
|
||||
if end_date > max_validity_end:
|
||||
end_date = max_validity_end
|
||||
|
|
|
@ -14,8 +14,6 @@ def config_mock(*args):
|
|||
"DIGICERT_ORG_ID": 111111,
|
||||
"DIGICERT_PRIVATE": False,
|
||||
"DIGICERT_DEFAULT_SIGNING_ALGORITHM": "sha256",
|
||||
"DIGICERT_DEFAULT_VALIDITY": 1,
|
||||
"DIGICERT_MAX_VALIDITY": 2,
|
||||
"DIGICERT_CIS_PROFILE_NAMES": {"digicert": 'digicert'},
|
||||
"DIGICERT_CIS_SIGNING_ALGORITHMS": {"digicert": 'digicert'},
|
||||
}
|
||||
|
@ -24,19 +22,18 @@ def config_mock(*args):
|
|||
|
||||
@patch("lemur.plugins.lemur_digicert.plugin.current_app")
|
||||
def test_determine_validity_years(mock_current_app):
|
||||
mock_current_app.config.get = Mock(return_value=2)
|
||||
assert plugin.determine_validity_years(1) == 1
|
||||
assert plugin.determine_validity_years(0) == 2
|
||||
assert plugin.determine_validity_years(3) == 2
|
||||
assert plugin.determine_validity_years(0) == 1
|
||||
assert plugin.determine_validity_years(3) == 1
|
||||
|
||||
|
||||
@patch("lemur.plugins.lemur_digicert.plugin.current_app")
|
||||
def test_determine_end_date(mock_current_app):
|
||||
mock_current_app.config.get = Mock(return_value=2)
|
||||
mock_current_app.config.get = Mock(return_value=397) # 397 days validity
|
||||
with freeze_time(time_to_freeze=arrow.get(2016, 11, 3).datetime):
|
||||
assert arrow.get(2018, 11, 3) == plugin.determine_end_date(0)
|
||||
assert arrow.get(2018, 5, 7) == plugin.determine_end_date(arrow.get(2018, 5, 7))
|
||||
assert arrow.get(2018, 11, 3) == plugin.determine_end_date(arrow.get(2020, 5, 7))
|
||||
assert arrow.get(2017, 12, 5) == plugin.determine_end_date(0) # 397 days from (2016, 11, 3)
|
||||
assert arrow.get(2017, 12, 5) == plugin.determine_end_date(arrow.get(2017, 12, 5))
|
||||
assert arrow.get(2017, 12, 5) == plugin.determine_end_date(arrow.get(2020, 5, 7))
|
||||
|
||||
|
||||
@patch("lemur.plugins.lemur_digicert.plugin.current_app")
|
||||
|
@ -52,7 +49,7 @@ def test_map_fields_with_validity_years(mock_current_app):
|
|||
"owner": "bob@example.com",
|
||||
"description": "test certificate",
|
||||
"extensions": {"sub_alt_names": {"names": [x509.DNSName(x) for x in names]}},
|
||||
"validity_years": 2
|
||||
"validity_years": 1
|
||||
}
|
||||
expected = {
|
||||
"certificate": {
|
||||
|
@ -62,7 +59,7 @@ def test_map_fields_with_validity_years(mock_current_app):
|
|||
"signature_hash": "sha256",
|
||||
},
|
||||
"organization": {"id": 111111},
|
||||
"validity_years": 2,
|
||||
"validity_years": 1,
|
||||
}
|
||||
assert expected == plugin.map_fields(options, CSR_STR)
|
||||
|
||||
|
|
Loading…
Reference in New Issue