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
|
@ -155,6 +155,22 @@ Specifying the `SQLALCHEMY_MAX_OVERFLOW` to 0 will enforce limit to not create c
|
||||||
|
|
||||||
LEMUR_ENCRYPTION_KEYS = ['1YeftooSbxCiX2zo8m1lXtpvQjy27smZcUUaGmffhMY=', 'LAfQt6yrkLqOK5lwpvQcT4jf2zdeTQJV1uYeh9coT5s=']
|
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
|
.. data:: DEBUG_DUMP
|
||||||
:noindex:
|
: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
|
This is the root to be used for your CA chain
|
||||||
|
|
||||||
|
|
||||||
.. data:: DIGICERT_DEFAULT_VALIDITY
|
.. data:: DIGICERT_DEFAULT_VALIDITY_DAYS
|
||||||
:noindex:
|
: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:
|
: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
|
.. data:: DIGICERT_PRIVATE
|
||||||
|
|
|
@ -152,6 +152,18 @@ def dates(data):
|
||||||
data["authority"].authority_certificate.not_after
|
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
|
return data
|
||||||
|
|
||||||
|
|
|
@ -61,18 +61,16 @@ def signature_hash(signing_algorithm):
|
||||||
|
|
||||||
|
|
||||||
def determine_validity_years(years):
|
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)
|
Considering maximum allowed certificate validity period of 397 days, this method should not return
|
||||||
max_years = current_app.config.get("DIGICERT_MAX_VALIDITY", default_years)
|
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:
|
:param years:
|
||||||
return max_years
|
:return: 1
|
||||||
if years not in [1, 2, 3]:
|
"""
|
||||||
return default_years
|
return 1
|
||||||
return years
|
|
||||||
|
|
||||||
|
|
||||||
def determine_end_date(end_date):
|
def determine_end_date(end_date):
|
||||||
|
@ -82,11 +80,11 @@ def determine_end_date(end_date):
|
||||||
:param end_date:
|
:param end_date:
|
||||||
:return: validity_end
|
:return: validity_end
|
||||||
"""
|
"""
|
||||||
default_years = current_app.config.get("DIGICERT_DEFAULT_VALIDITY", 1)
|
default_days = current_app.config.get("DIGICERT_DEFAULT_VALIDITY_DAYS", 397)
|
||||||
max_validity_end = arrow.utcnow().shift(years=current_app.config.get("DIGICERT_MAX_VALIDITY", default_years))
|
max_validity_end = arrow.utcnow().shift(days=current_app.config.get("DIGICERT_MAX_VALIDITY_DAYS", default_days))
|
||||||
|
|
||||||
if not end_date:
|
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:
|
if end_date > max_validity_end:
|
||||||
end_date = max_validity_end
|
end_date = max_validity_end
|
||||||
|
|
|
@ -14,8 +14,6 @@ def config_mock(*args):
|
||||||
"DIGICERT_ORG_ID": 111111,
|
"DIGICERT_ORG_ID": 111111,
|
||||||
"DIGICERT_PRIVATE": False,
|
"DIGICERT_PRIVATE": False,
|
||||||
"DIGICERT_DEFAULT_SIGNING_ALGORITHM": "sha256",
|
"DIGICERT_DEFAULT_SIGNING_ALGORITHM": "sha256",
|
||||||
"DIGICERT_DEFAULT_VALIDITY": 1,
|
|
||||||
"DIGICERT_MAX_VALIDITY": 2,
|
|
||||||
"DIGICERT_CIS_PROFILE_NAMES": {"digicert": 'digicert'},
|
"DIGICERT_CIS_PROFILE_NAMES": {"digicert": 'digicert'},
|
||||||
"DIGICERT_CIS_SIGNING_ALGORITHMS": {"digicert": 'digicert'},
|
"DIGICERT_CIS_SIGNING_ALGORITHMS": {"digicert": 'digicert'},
|
||||||
}
|
}
|
||||||
|
@ -24,19 +22,18 @@ def config_mock(*args):
|
||||||
|
|
||||||
@patch("lemur.plugins.lemur_digicert.plugin.current_app")
|
@patch("lemur.plugins.lemur_digicert.plugin.current_app")
|
||||||
def test_determine_validity_years(mock_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(1) == 1
|
||||||
assert plugin.determine_validity_years(0) == 2
|
assert plugin.determine_validity_years(0) == 1
|
||||||
assert plugin.determine_validity_years(3) == 2
|
assert plugin.determine_validity_years(3) == 1
|
||||||
|
|
||||||
|
|
||||||
@patch("lemur.plugins.lemur_digicert.plugin.current_app")
|
@patch("lemur.plugins.lemur_digicert.plugin.current_app")
|
||||||
def test_determine_end_date(mock_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):
|
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(2017, 12, 5) == plugin.determine_end_date(0) # 397 days from (2016, 11, 3)
|
||||||
assert arrow.get(2018, 5, 7) == plugin.determine_end_date(arrow.get(2018, 5, 7))
|
assert arrow.get(2017, 12, 5) == plugin.determine_end_date(arrow.get(2017, 12, 5))
|
||||||
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(arrow.get(2020, 5, 7))
|
||||||
|
|
||||||
|
|
||||||
@patch("lemur.plugins.lemur_digicert.plugin.current_app")
|
@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",
|
"owner": "bob@example.com",
|
||||||
"description": "test certificate",
|
"description": "test certificate",
|
||||||
"extensions": {"sub_alt_names": {"names": [x509.DNSName(x) for x in names]}},
|
"extensions": {"sub_alt_names": {"names": [x509.DNSName(x) for x in names]}},
|
||||||
"validity_years": 2
|
"validity_years": 1
|
||||||
}
|
}
|
||||||
expected = {
|
expected = {
|
||||||
"certificate": {
|
"certificate": {
|
||||||
|
@ -62,7 +59,7 @@ def test_map_fields_with_validity_years(mock_current_app):
|
||||||
"signature_hash": "sha256",
|
"signature_hash": "sha256",
|
||||||
},
|
},
|
||||||
"organization": {"id": 111111},
|
"organization": {"id": 111111},
|
||||||
"validity_years": 2,
|
"validity_years": 1,
|
||||||
}
|
}
|
||||||
assert expected == plugin.map_fields(options, CSR_STR)
|
assert expected == plugin.map_fields(options, CSR_STR)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue