Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions tests/test_local_methods.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,26 @@ def test_parse_cloud_zone1(self):
self.assertEqual(p.key_types[1].option, 4096)
self.assertTrue(len(p.key_types) == 2)

def test_parse_policy_skips_unsupported_key_entries(self):
# A CIT/policy may advertise key sizes/curves the client cannot represent (real example:
# DigiCert/ZTPKI zones on NGTS advertise RSA 1024). The parse must skip those entries, not
# raise BadData and brick read_zone_conf/get_policy/enrollment for the whole zone.
conn = CloudConnection(token="")
cit = {
"id": "cit-1",
"name": "RequestPolicyDC",
"certificateAuthority": "DIGICERT",
"keyTypes": [
{"keyType": "RSA", "keyLengths": [2048, 1024, 4096]},
{"keyType": "EC", "keyCurves": ["P256", "brainpoolP256r1", "P384"]},
],
}
p = conn._parse_policy_response_to_object(cit) # must not raise
rsa = [kt.option for kt in p.key_types if kt.key_type == KeyType.RSA]
ec = [kt.option for kt in p.key_types if kt.key_type == KeyType.ECDSA]
self.assertEqual(rsa, [2048, 4096]) # unsupported 1024 dropped
self.assertEqual(ec, ["p256", "p384"]) # unknown brainpool dropped; curves normalized lowercase

# cloud doesnt support ecdsa yet. may be can be enabled in the future
# def test_parse_cloud_zone2(self):
# conn = CloudConnection(token="")
Expand Down
27 changes: 20 additions & 7 deletions vcert/connection_cloud.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
from .common import (ZoneConfig, CertificateRequest, CommonConnection, Policy, RevocationRequest, get_ip_address,
log_errors, MIME_JSON, MIME_TEXT, MIME_ANY, CertField, KeyType, DEFAULT_TIMEOUT,
CSR_ORIGIN_SERVICE, CHAIN_OPTION_FIRST, CHAIN_OPTION_LAST)
from .errors import (VenafiConnectionError, ServerUnexptedBehavior, ClientBadData, CertificateRequestError,
from .errors import (VenafiConnectionError, ServerUnexptedBehavior, ClientBadData, BadData, CertificateRequestError,
CertificateRenewError, CertificateRevokeError, VenafiError, RetrieveCertificateTimeoutError)
from .http_status import HTTPStatus
from .logger import get_child
Expand Down Expand Up @@ -326,11 +326,20 @@ def _parse_policy_response_to_object(d):
for kt in d.get('keyTypes', []):
key_type = kt['keyType'].lower()
if key_type == KeyType.RSA:
for s in kt['keyLengths']:
policy.key_types.append(KeyType(key_type, s))
for s in kt.get('keyLengths', []):
try:
policy.key_types.append(KeyType(key_type, s))
except (BadData, KeyError):
# A policy may advertise key sizes the client cannot represent (e.g. RSA 1024).
# Skip them instead of failing the whole policy parse - this keeps read_zone_conf /
# get_policy / enrollment working against such zones (Go tolerates unknown sizes).
log.warning(f"Ignoring unsupported RSA key length advertised by policy: {s}")
elif key_type == KeyType.ECDSA:
for s in kt["keyCurves"]:
policy.key_types.append(KeyType(key_type, s))
for s in kt.get("keyCurves", []):
try:
policy.key_types.append(KeyType(key_type, s))
except (BadData, KeyError):
log.warning(f"Ignoring unsupported EC curve advertised by policy: {s}")
else:
log.error(f"Unknown key type: {kt['keyType']}")
raise ServerUnexptedBehavior
Expand Down Expand Up @@ -359,8 +368,12 @@ def _parse_recommended_settings_to_object(d):
k_type = key['type']
kl = key['length'] if 'length' in key else None
kc = key['curve'] if 'curve' in key else None
kt = KeyType(k_type, kl or kc)
settings.keyType = kt
try:
settings.keyType = KeyType(k_type, kl or kc)
except (BadData, KeyError):
# Same resilience as the keyTypes loop: a recommended key the client cannot
# represent must not abort the whole policy parse.
log.warning(f"Ignoring unsupported recommended key in policy: {k_type} {kl or kc}")

return settings

Expand Down