diff --git a/requirements-build.txt b/requirements-build.txt index 8671f14..5c60c2d 100644 --- a/requirements-build.txt +++ b/requirements-build.txt @@ -1,4 +1,4 @@ -pip==23.3.2 +pip==25.0.1 pytest==7.4.3 pytest-cov==4.1.0 safety==2.3.5 diff --git a/vcert/common.py b/vcert/common.py index d862634..cbb2546 100644 --- a/vcert/common.py +++ b/vcert/common.py @@ -1,5 +1,5 @@ # -# Copyright 2019 Venafi, Inc. +# Copyright 2019-2025 Venafi, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -632,6 +632,12 @@ def auth(self): """ raise NotImplementedError + def get_version(self): + """ + Gets version string + """ + raise NotImplementedError + def request_cert(self, request, zone): """ Making request to certificate. It will generate CSR from data if CSR not specified, generate key if required and send to server for signing. Set request.id for retrieving certificate. @@ -765,5 +771,5 @@ def __new__(cls, value, description): return obj FAKE = 100, "Connector for testing purposes" - TPP = 200, "Trust Protection Platfom" + TPP = 200, "Trust Protection Platform" VAAS = 400, "Venafi as a Service" diff --git a/vcert/connection_cloud.py b/vcert/connection_cloud.py index 84f3c5d..37c166c 100644 --- a/vcert/connection_cloud.py +++ b/vcert/connection_cloud.py @@ -1,5 +1,5 @@ # -# Copyright 2019 Venafi, Inc. +# Copyright 2019-2025 Venafi, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -340,6 +340,9 @@ def auth(self): if status == HTTPStatus.OK: return data + def get_version(self): + raise NotImplementedError + def _get_app_details_by_name(self, app_name): """ :param str app_name: diff --git a/vcert/connection_fake.py b/vcert/connection_fake.py index 2a6f209..091f81a 100644 --- a/vcert/connection_fake.py +++ b/vcert/connection_fake.py @@ -1,5 +1,5 @@ # -# Copyright 2022 Venafi, Inc. +# Copyright 2022-2025 Venafi, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -112,6 +112,9 @@ def __str__(self): def auth(self): return fake_user() + def get_version(self): + return "25.1.0.3419" + def register(self, email): return fake_user(email) diff --git a/vcert/connection_tpp_abstract.py b/vcert/connection_tpp_abstract.py index 567cfaf..e5a0acc 100644 --- a/vcert/connection_tpp_abstract.py +++ b/vcert/connection_tpp_abstract.py @@ -1,5 +1,5 @@ # -# Copyright 2020 Venafi, Inc. +# Copyright 2020-2025 Venafi, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -52,6 +52,7 @@ class URLS: REVOKE_TOKEN = API_TOKEN_URL + "revoke/token" # type: str AUTHORIZE = API_BASE_URL + "authorize/" + VERSION = API_BASE_URL + "systemstatus/version" CERTIFICATE_REQUESTS = API_BASE_URL + "certificates/request" CERTIFICATE_RETRIEVE = API_BASE_URL + "certificates/retrieve" FIND_POLICY = API_BASE_URL + "config/findpolicy" @@ -99,6 +100,13 @@ def __init__(self): def auth(self): raise NotImplementedError + def get_version(self): + args = { self.ARG_URL: URLS.VERSION } + status, data = self.get(args=args) + if status != HTTPStatus.OK: + raise ServerUnexptedBehavior(f"Server returns {status} status on get version") + return data['Version'] + def request_cert(self, request, zone): request_data = { 'PolicyDN': self._normalize_zone(zone), @@ -591,14 +599,35 @@ def set_policy(self, zone, policy_spec): self._set_policy_attr(name, SPA.TPP_STATE, [tpp_policy.state.value], tpp_policy.state.locked) if tpp_policy.country: self._set_policy_attr(name, SPA.TPP_COUNTRY, [tpp_policy.country.value], tpp_policy.state.locked) - if tpp_policy.key_algo: - self._set_policy_attr(name, SPA.TPP_KEY_ALGORITHM, [tpp_policy.key_algo.value], tpp_policy.key_algo.locked) - if tpp_policy.key_bit_str: - self._set_policy_attr(name, SPA.TPP_KEY_BIT_STR, [tpp_policy.key_bit_str.value], - tpp_policy.key_bit_str.locked) - if tpp_policy.elliptic_curve: - self._set_policy_attr(name, SPA.TPP_ELLIPTIC_CURVE, [tpp_policy.elliptic_curve.value], - tpp_policy.elliptic_curve.locked) + + # Check the TPP version is 25.x or greater + tpp_version_number = -1 + tpp_version = self.get_version() + if tpp_version and "." in tpp_version: + tpp_version_number = int(tpp_version.split(".")[0]) + if tpp_version_number >= 25: + # Create "PKIX Parameter Set" attributes + if tpp_policy.pkix_parameter_set: + self._set_policy_attr(name, SPA.TPP_PKIX_PARAMETER_SET_POLICY, [tpp_policy.pkix_parameter_set.value], tpp_policy.pkix_parameter_set.locked) + else: + # For backward compatibility, if the "PKIX Parameter Set" is not set, we need to set it using the "Key Algorithm", + # "Key Bit Strength" and "Elliptic Curve" attribute values + pkixOid = tpp_policy.pkix_parameter_set_from_old_key_attributes() + if pkixOid: + self._set_policy_attr(name, SPA.TPP_PKIX_PARAMETER_SET_POLICY, [pkixOid], tpp_policy.key_algo.locked) + self._set_policy_attr(name, SPA.TPP_PKIX_PARAMETER_SET_POLICY_DEFAULT, [pkixOid], tpp_policy.key_algo.locked) + if tpp_policy.pkix_parameter_set_default: + self._set_policy_attr(name, SPA.TPP_PKIX_PARAMETER_SET_POLICY_DEFAULT, [tpp_policy.pkix_parameter_set_default.value], tpp_policy.pkix_parameter_set_default.locked) + else: + if tpp_policy.key_algo: + self._set_policy_attr(name, SPA.TPP_KEY_ALGORITHM, [tpp_policy.key_algo.value], tpp_policy.key_algo.locked) + if tpp_policy.key_bit_str: + self._set_policy_attr(name, SPA.TPP_KEY_BIT_STR, [tpp_policy.key_bit_str.value], + tpp_policy.key_bit_str.locked) + if tpp_policy.elliptic_curve: + self._set_policy_attr(name, SPA.TPP_ELLIPTIC_CURVE, [tpp_policy.elliptic_curve.value], + tpp_policy.elliptic_curve.locked) + if tpp_policy.management_type: self._set_policy_attr(name, SPA.TPP_MANAGEMENT_TYPE, [tpp_policy.management_type.value], tpp_policy.management_type.locked) diff --git a/vcert/policy/__init__.py b/vcert/policy/__init__.py index 11d590f..8e64149 100644 --- a/vcert/policy/__init__.py +++ b/vcert/policy/__init__.py @@ -1,5 +1,5 @@ # -# Copyright 2021 Venafi, Inc. +# Copyright 2021-2025 Venafi, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -62,6 +62,8 @@ def __init__(self): TPP_PROHIBIT_WILDCARD = 'Prohibit Wildcard' TPP_DOMAIN_SUFFIX_WHITELIST = 'Domain Suffix Whitelist' TPP_ORG_UNIT = 'Organizational Unit' + TPP_PKIX_PARAMETER_SET_POLICY = 'PKIX Parameter Set Policy' + TPP_PKIX_PARAMETER_SET_POLICY_DEFAULT = 'PKIX Parameter Set Policy Default' TPP_KEY_ALGORITHM = 'Key Algorithm' TPP_KEY_BIT_STR = 'Key Bit Strength' TPP_ELLIPTIC_CURVE = 'Elliptic Curve' diff --git a/vcert/policy/pm_tpp.py b/vcert/policy/pm_tpp.py index de0b89d..f9475ab 100644 --- a/vcert/policy/pm_tpp.py +++ b/vcert/policy/pm_tpp.py @@ -1,5 +1,5 @@ # -# Copyright 2021 Venafi, Inc. +# Copyright 2021-2025 Venafi, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -56,6 +56,8 @@ def __init__(self): self.city = None self.state = None self.country = None + self.pkix_parameter_set = None + self.pkix_parameter_set_default = None self.key_algo = None self.key_bit_str = None self.elliptic_curve = None @@ -72,6 +74,31 @@ def __init__(self): self.allow_private_key_reuse = None self.want_renewal = None + def pkix_parameter_set_from_old_key_attributes(self): + """ + For backward compatibility, if the "PKIX Parameter Set" is not set, we need to set it using the "Key Algorithm", + "Key Bit Strength" and "Elliptic Curve" attribute values + """ + _key_algorithms_to_pkix = { + "RSA": { + "1024": "1.3.6.1.4.1.28783.10.1.1.1024", + "2048": "1.3.6.1.4.1.28783.10.1.1.2048", + "3072": "1.3.6.1.4.1.28783.10.1.1.3072", + "4096": "1.3.6.1.4.1.28783.10.1.1.4096", + }, + "ECC": { + "P256": "1.3.6.1.4.1.28783.10.2.1.256", + "P384": "1.3.6.1.4.1.28783.10.2.1.384", + "P521": "1.3.6.1.4.1.28783.10.2.1.521", + }, + } + if self.key_algo and self.key_algo.value and self.key_algo.value in _key_algorithms_to_pkix: + if self.key_algo.value.upper() != 'RSA' and self.elliptic_curve and self.elliptic_curve.value and self.elliptic_curve.value in _key_algorithms_to_pkix[self.key_algo.value]: + return _key_algorithms_to_pkix[self.key_algo.value][self.elliptic_curve.value] + if self.key_bit_str and self.key_bit_str.value and str(self.key_bit_str.value) in _key_algorithms_to_pkix[self.key_algo.value]: + return _key_algorithms_to_pkix[self.key_algo.value][str(self.key_bit_str.value)] + return None + def to_policy_spec(self): """ :rtype: PolicySpecification diff --git a/vcert/policy/policy_spec.py b/vcert/policy/policy_spec.py index 813efd7..5a9edd5 100644 --- a/vcert/policy/policy_spec.py +++ b/vcert/policy/policy_spec.py @@ -1,5 +1,5 @@ # -# Copyright 2021 Venafi, Inc. +# Copyright 2021-2025 Venafi, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -76,19 +76,21 @@ def __init__(self, orgs=None, org_units=None, localities=None, states=None, coun class KeyPair: def __init__(self, key_types=None, rsa_key_sizes=None, elliptic_curves=None, service_generated=None, - reuse_allowed=None): + reuse_allowed=None, pkix_parameter_set=None): """ :param list[str] key_types: :param list[int] rsa_key_sizes: :param list[str] elliptic_curves: :param bool service_generated: :param bool reuse_allowed: + :param list[str] pkix_parameter_set """ self.key_types = key_types if key_types else [] self.rsa_key_sizes = rsa_key_sizes if rsa_key_sizes else [] self.elliptic_curves = elliptic_curves if elliptic_curves else [] self.service_generated = service_generated self.reuse_allowed = reuse_allowed + self.pkix_parameter_set = pkix_parameter_set if pkix_parameter_set else [] class SubjectAltNames: @@ -143,14 +145,17 @@ def __init__(self, org=None, org_units=None, locality=None, state=None, country= class DefaultKeyPair: - def __init__(self, key_type=None, rsa_key_size=None, elliptic_curve=None, service_generated=None): + def __init__(self, key_type=None, rsa_key_size=None, elliptic_curve=None, service_generated=None, + pkix_parameter_set_default=None): """ :param str key_type: :param int rsa_key_size: :param str elliptic_curve: :param bool service_generated: + :param str pkix_parameter_set_default: """ self.key_type = key_type self.rsa_key_size = rsa_key_size self.elliptic_curve = elliptic_curve self.service_generated = service_generated + self.pkix_parameter_set_default = pkix_parameter_set_default