From 7a83799bcd9fe9292dc9bd3fe91b8d629aae3585 Mon Sep 17 00:00:00 2001 From: sayali Date: Mon, 10 Aug 2020 17:30:34 -0700 Subject: [PATCH 1/9] Cert validity should not exceed 397 days for publicly trusted issuers --- lemur/common/validators.py | 12 ++++++++++++ lemur/plugins/lemur_digicert/plugin.py | 6 +++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/lemur/common/validators.py b/lemur/common/validators.py index e1dfe3c1..4aecb97e 100644 --- a/lemur/common/validators.py +++ b/lemur/common/validators.py @@ -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", []) + 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 diff --git a/lemur/plugins/lemur_digicert/plugin.py b/lemur/plugins/lemur_digicert/plugin.py index e5c4b2ce..32a5375a 100644 --- a/lemur/plugins/lemur_digicert/plugin.py +++ b/lemur/plugins/lemur_digicert/plugin.py @@ -82,11 +82,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 From 18a3514974a7bd40c971e303df7ffd573b484c69 Mon Sep 17 00:00:00 2001 From: sayali Date: Mon, 10 Aug 2020 18:06:45 -0700 Subject: [PATCH 2/9] Renaming PUBLIC_CA to PUBLIC_CA_AUTHORITY_NAMES --- lemur/common/validators.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lemur/common/validators.py b/lemur/common/validators.py index 4aecb97e..74095255 100644 --- a/lemur/common/validators.py +++ b/lemur/common/validators.py @@ -155,7 +155,7 @@ def dates(data): # 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", []) + 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 ( From 682991c02277d899aa43763c20a5e999a6713529 Mon Sep 17 00:00:00 2001 From: sayali Date: Mon, 10 Aug 2020 18:07:46 -0700 Subject: [PATCH 3/9] Updating Lemur docs to capture Digicert validity config changes --- docs/administration.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/administration.rst b/docs/administration.rst index 157af478..a6d93af7 100644 --- a/docs/administration.rst +++ b/docs/administration.rst @@ -729,16 +729,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 From 0d1798b0e0a2bc96bea5635093db96f8cd658fa4 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2020 13:43:11 +0000 Subject: [PATCH 4/9] Bump cloudflare from 2.8.8 to 2.8.9 Bumps [cloudflare](https://github.com/cloudflare/python-cloudflare) from 2.8.8 to 2.8.9. - [Release notes](https://github.com/cloudflare/python-cloudflare/releases) - [Changelog](https://github.com/cloudflare/python-cloudflare/blob/master/CHANGELOG.md) - [Commits](https://github.com/cloudflare/python-cloudflare/compare/2.8.8...2.8.9) Signed-off-by: dependabot-preview[bot] --- requirements-docs.txt | 2 +- requirements.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements-docs.txt b/requirements-docs.txt index 3d1ed54c..a154dbef 100644 --- a/requirements-docs.txt +++ b/requirements-docs.txt @@ -25,7 +25,7 @@ certsrv==2.1.1 # via -r requirements.txt cffi==1.14.0 # via -r requirements.txt, bcrypt, cryptography, pynacl chardet==3.0.4 # via -r requirements.txt, requests click==7.1.1 # via -r requirements.txt, flask -cloudflare==2.8.8 # via -r requirements.txt +cloudflare==2.8.9 # via -r requirements.txt cryptography==3.0 # via -r requirements.txt, acme, josepy, paramiko, pyopenssl, requests dnspython3==1.15.0 # via -r requirements.txt dnspython==1.15.0 # via -r requirements.txt, dnspython3 diff --git a/requirements.txt b/requirements.txt index 46723b0d..d9e86d97 100644 --- a/requirements.txt +++ b/requirements.txt @@ -23,7 +23,7 @@ certsrv==2.1.1 # via -r requirements.in cffi==1.14.0 # via bcrypt, cryptography, pynacl chardet==3.0.4 # via requests click==7.1.1 # via flask -cloudflare==2.8.8 # via -r requirements.in +cloudflare==2.8.9 # via -r requirements.in cryptography==3.0 # via -r requirements.in, acme, josepy, paramiko, pyopenssl, requests dnspython3==1.15.0 # via -r requirements.in dnspython==1.15.0 # via dnspython3 From 226a62d338c89e7111759370b6616778798b830d Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 11 Aug 2020 01:40:26 +0000 Subject: [PATCH 5/9] Bump sphinx from 3.1.2 to 3.2.0 Bumps [sphinx](https://github.com/sphinx-doc/sphinx) from 3.1.2 to 3.2.0. - [Release notes](https://github.com/sphinx-doc/sphinx/releases) - [Changelog](https://github.com/sphinx-doc/sphinx/blob/3.x/CHANGES) - [Commits](https://github.com/sphinx-doc/sphinx/compare/v3.1.2...v3.2.0) Signed-off-by: dependabot-preview[bot] --- requirements-docs.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-docs.txt b/requirements-docs.txt index a154dbef..7e187213 100644 --- a/requirements-docs.txt +++ b/requirements-docs.txt @@ -92,7 +92,7 @@ six==1.15.0 # via -r requirements.txt, acme, bcrypt, cryptography, snowballstemmer==2.0.0 # via sphinx soupsieve==2.0.1 # via -r requirements.txt, beautifulsoup4 sphinx-rtd-theme==0.5.0 # via -r requirements-docs.in -sphinx==3.1.2 # via -r requirements-docs.in, sphinx-rtd-theme, sphinxcontrib-httpdomain +sphinx==3.2.0 # via -r requirements-docs.in, sphinx-rtd-theme, sphinxcontrib-httpdomain sphinxcontrib-applehelp==1.0.2 # via sphinx sphinxcontrib-devhelp==1.0.2 # via sphinx sphinxcontrib-htmlhelp==1.0.3 # via sphinx From bde2829e720f31129347db281ba2984eea7a5b4f Mon Sep 17 00:00:00 2001 From: sayali Date: Tue, 11 Aug 2020 17:10:29 -0700 Subject: [PATCH 6/9] Modify unit test test_determine_end_date to match new config --- lemur/plugins/lemur_digicert/tests/test_digicert.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lemur/plugins/lemur_digicert/tests/test_digicert.py b/lemur/plugins/lemur_digicert/tests/test_digicert.py index 8bfd1dcf..ca2ddf68 100644 --- a/lemur/plugins/lemur_digicert/tests/test_digicert.py +++ b/lemur/plugins/lemur_digicert/tests/test_digicert.py @@ -32,11 +32,11 @@ def test_determine_validity_years(mock_current_app): @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") From d7ca1570beb44a62ac79ac96052a420ade5ba028 Mon Sep 17 00:00:00 2001 From: sayali Date: Tue, 11 Aug 2020 18:02:42 -0700 Subject: [PATCH 7/9] maximum 1 year validity for digicert --- lemur/plugins/lemur_digicert/plugin.py | 18 ++++++++---------- .../lemur_digicert/tests/test_digicert.py | 11 ++++------- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/lemur/plugins/lemur_digicert/plugin.py b/lemur/plugins/lemur_digicert/plugin.py index 32a5375a..9b3d4429 100644 --- a/lemur/plugins/lemur_digicert/plugin.py +++ b/lemur/plugins/lemur_digicert/plugin.py @@ -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 398 days, this method should not return + more than 1 year of validity. Thus changing it to 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): diff --git a/lemur/plugins/lemur_digicert/tests/test_digicert.py b/lemur/plugins/lemur_digicert/tests/test_digicert.py index ca2ddf68..4abfcf54 100644 --- a/lemur/plugins/lemur_digicert/tests/test_digicert.py +++ b/lemur/plugins/lemur_digicert/tests/test_digicert.py @@ -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,10 +22,9 @@ 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") @@ -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) From acb04638440a5b191ac4015212adfae58934f78c Mon Sep 17 00:00:00 2001 From: sayali Date: Tue, 11 Aug 2020 18:51:41 -0700 Subject: [PATCH 8/9] Add new configs to the doc --- docs/administration.rst | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/docs/administration.rst b/docs/administration.rst index a6d93af7..9f377119 100644 --- a/docs/administration.rst +++ b/docs/administration.rst @@ -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: From 6ff8910f873051298a99d88ee9c586cb508a2594 Mon Sep 17 00:00:00 2001 From: sayali Date: Tue, 11 Aug 2020 18:53:19 -0700 Subject: [PATCH 9/9] mention 397 for digicert plugin --- lemur/plugins/lemur_digicert/plugin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lemur/plugins/lemur_digicert/plugin.py b/lemur/plugins/lemur_digicert/plugin.py index 9b3d4429..fd8c4e2d 100644 --- a/lemur/plugins/lemur_digicert/plugin.py +++ b/lemur/plugins/lemur_digicert/plugin.py @@ -62,8 +62,8 @@ def signature_hash(signing_algorithm): def determine_validity_years(years): """ - Considering maximum allowed certificate validity period of 398 days, this method should not return - more than 1 year of validity. Thus changing it to return 1. + 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.