Skip to content

Commit e80788a

Browse files
committed
Support for EC KeyTypes in Policy Specification
Added support for Elliptic Curve Key types when creating policies in VaaS
1 parent fdd0d48 commit e80788a

3 files changed

Lines changed: 137 additions & 41 deletions

File tree

tests/test_pm.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
from test_env import (TPP_TOKEN_URL, CLOUD_APIKEY, CLOUD_URL, TPP_PM_ROOT, CLOUD_ENTRUST_CA_NAME,
2121
CLOUD_DIGICERT_CA_NAME, TPP_CA_NAME, TPP_USER, TPP_PASSWORD)
2222
from test_utils import timestamp
23-
from vcert import TPPTokenConnection, CloudConnection, Authentication, SCOPE_PM, logger, VenafiError
23+
from vcert import TPPTokenConnection, CloudConnection, Authentication, SCOPE_PM, logger, VenafiError, KeyType
2424
from vcert.parser import json_parser, yaml_parser
2525
from vcert.parser.utils import parse_policy_spec
2626
from vcert.policy import (Policy, Subject, KeyPair, SubjectAltNames, Defaults, DefaultSubject, DefaultKeyPair,
@@ -182,6 +182,28 @@ def test_csr_attributes_not_specified(self):
182182
self.assertTrue(cit.csr_upload_allowed, "csrUploadAllowed attribute is not True")
183183
self.assertTrue(cit.key_generated_by_venafi_allowed, "keyGeneratedByVenafiAllowed is not True")
184184

185+
def test_ec_key_pair(self):
186+
policy = _get_policy_obj()
187+
kp = KeyPair(
188+
key_types=['EC'],
189+
rsa_key_sizes=[2048, 4096],
190+
elliptic_curves=['P521', 'P384'],
191+
reuse_allowed=False)
192+
policy.key_pair = kp
193+
194+
defaults = _get_defaults_obj()
195+
defaults.key_pair = DefaultKeyPair(
196+
key_type='EC',
197+
rsa_key_size=2048,
198+
elliptic_curve='P521')
199+
200+
ps = self._create_policy_cloud(policy=policy, defaults=defaults)
201+
self.assertEqual(ps.policy.key_pair.key_types[0].upper(), KeyType.ECDSA.upper(), "Policy Key Type is not EC")
202+
self.assertTrue(len(ps.policy.key_pair.elliptic_curves) == 2,
203+
f"Expected 2 accepted Elliptic Curves. Got {len(ps.policy.key_pair.elliptic_curves)}")
204+
self.assertIn('P521', ['P521', 'P384'], "[P521] is not in the allowed Elliptic Curves list")
205+
self.assertIn('P384', ['P521', 'P384'], "[P384] is not in the allowed Elliptic Curves list")
206+
185207
def _create_policy_cloud(self, policy_spec=None, policy=None, defaults=None):
186208
zone = self._get_random_zone()
187209
response = create_policy(self.cloud_conn, zone, policy_spec, policy, defaults)

vcert/connection_cloud.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,9 @@ def _parse_policy_response_to_object(d):
256256
if key_type == KeyType.RSA:
257257
for s in kt['keyLengths']:
258258
policy.key_types.append(KeyType(key_type, s))
259+
elif key_type == KeyType.ECDSA:
260+
for s in kt["keyCurves"]:
261+
policy.key_types.append(KeyType(key_type, s))
259262
else:
260263
log.error(f"Unknown key type: {kt['keyType']}")
261264
raise ServerUnexptedBehavior
@@ -280,7 +283,11 @@ def _parse_recommended_settings_to_object(d):
280283
rs['keyReuse'] if 'keyReuse' in rs else None
281284
)
282285
if 'key' in rs:
283-
kt = KeyType(rs['key']['type'], rs['key']['length'])
286+
key = rs['key']
287+
k_type = key['type']
288+
kl = key['length'] if 'length' in key else None
289+
kc = key['curve'] if 'curve' in key else None
290+
kt = KeyType(k_type, kl or kc)
284291
settings.keyType = kt
285292

286293
return settings

vcert/policy/pm_cloud.py

Lines changed: 106 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020
Defaults, SubjectAltNames)
2121
from vcert.vaas_utils import AppDetails
2222

23-
supported_rsa_key_sizes = [1024, 2048, 4096]
23+
supported_rsa_key_sizes = [1024, 2048, 3072, 4096]
24+
supported_elliptic_curves = ["P256", "P384", "P521", "ED25519"]
2425
CA_TYPE_DIGICERT = 'DIGICERT'
2526
CA_TYPE_ENTRUST = 'ENTRUST'
2627
REQUESTER_NAME = 'Venafi Cloud Service'
@@ -90,17 +91,20 @@ def build_policy_spec(cit, ca_info, subject_cn_to_str=True):
9091
create_kp = False
9192
if len(cit.key_types) > 0:
9293
key_types = []
93-
key_sizes = []
94-
for allowed_kt in cit.key_types:
95-
kt = allowed_kt.key_type
96-
kl = allowed_kt.option
94+
rsa_key_sizes = []
95+
elliptic_curves = []
96+
for kt in cit.key_types:
97+
if kt.key_type.upper() == KeyType.RSA.upper():
98+
rsa_key_sizes.append(kt.option)
99+
elif kt.key_type.upper() == KeyType.ECDSA.upper():
100+
elliptic_curves.append(kt.option)
97101
# Only include one instance of the KeyType
98-
if kt not in key_types:
99-
key_types.append(kt)
100-
key_sizes.append(kl)
102+
if kt.key_type.upper() not in key_types:
103+
key_types.append(kt.key_type.upper())
101104
create_kp = True
102105
kp.key_types = key_types
103-
kp.rsa_key_sizes = key_sizes
106+
kp.rsa_key_sizes = rsa_key_sizes
107+
kp.elliptic_curves = elliptic_curves
104108

105109
kp.reuse_allowed = cit.key_reuse
106110
if cit.key_generated_by_venafi_allowed is True and cit.csr_upload_allowed is True:
@@ -149,11 +153,13 @@ def build_policy_spec(cit, ca_info, subject_cn_to_str=True):
149153
dkp = DefaultKeyPair()
150154
create_dkp = False
151155
if kt.key_type:
152-
dkp.key_type = kt.key_type
153-
create_dkp = True
154-
if kt.option:
155-
dkp.rsa_key_size = kt.option
156156
create_dkp = True
157+
dkp.key_type = kt.key_type.upper()
158+
if kt.key_type == KeyType.RSA:
159+
dkp.rsa_key_size = kt.option
160+
elif kt.key_type == KeyType.ECDSA:
161+
dkp.elliptic_curve = kt.option
162+
157163
d.key_pair = dkp if create_dkp else None
158164

159165
ps.defaults = d
@@ -170,18 +176,26 @@ def validate_policy_spec(policy_spec):
170176

171177
# validate key pair values
172178
if policy_spec.policy.key_pair:
173-
if len(policy_spec.policy.key_pair.key_types) > 1:
174-
raise VenafiError("Key Type values exceeded. Only one Key Type is allowed by VaaS")
179+
key_types = _get_key_types_lowercase(policy_spec.policy.key_pair.key_types)
175180

176-
if policy_spec.policy.key_pair.key_types \
177-
and policy_spec.policy.key_pair.key_types[0].lower() != KeyType.RSA:
178-
raise VenafiError(f"Key Type [{p.key_pair.key_types[0]}] is not supported by VaaS")
181+
if len(key_types) > 2:
182+
raise VenafiError("Key Type values exceeded. Only RSA and EC Key Types are allowed by VaaS")
179183

180-
if len(policy_spec.policy.key_pair.rsa_key_sizes) > 0:
184+
if key_types:
185+
for kt in key_types:
186+
if kt not in [KeyType.RSA, KeyType.ECDSA]:
187+
raise VenafiError(f"Key Type [{kt}] is not supported by VaaS")
188+
189+
if KeyType.RSA in key_types and len(policy_spec.policy.key_pair.rsa_key_sizes) > 0:
181190
invalid_value = get_invalid_cloud_rsa_key_size_value(policy_spec.policy.key_pair.rsa_key_sizes)
182191
if invalid_value:
183192
raise VenafiError(f"The Key Size [{invalid_value}] is not supported by VaaS")
184193

194+
if KeyType.ECDSA in key_types and len(policy_spec.policy.key_pair.elliptic_curves) > 0:
195+
invalid_value = get_invalid_cloud_ec_value(policy_spec.policy.key_pair.elliptic_curves)
196+
if invalid_value:
197+
raise VenafiError(f"The Elliptic Curve [{invalid_value}] is not supported by VaaS")
198+
185199
# validate subject CN and SAN regexes
186200
if p.subject_alt_names:
187201
sans = get_sans(policy_spec.policy.subject_alt_names)
@@ -240,17 +254,31 @@ def validate_policy_spec(policy_spec):
240254
else:
241255
policy_spec.policy = Policy()
242256

243-
# validate default values when policy is not defined
257+
# validate default values regardless of policy being defined
244258
if policy_spec.defaults and policy_spec.defaults.key_pair:
245259
dkp = policy_spec.defaults.key_pair
246260

247-
if dkp.key_type and dkp.key_type != "RSA":
261+
if dkp.key_type and dkp.key_type.lower() not in [KeyType.RSA, KeyType.ECDSA]:
248262
raise VenafiError(f"Default Key Type [{dkp.key_type}] is not supported by VaaS")
249263

250264
if dkp.rsa_key_size:
251265
invalid_value = get_invalid_cloud_rsa_key_size_value([dkp.rsa_key_size])
252266
if invalid_value:
253-
raise VenafiError(f"Default Key Size [{invalid_value}] is not supported by VaaS")
267+
raise VenafiError(f"Default RSA Key Size [{invalid_value}] is not supported by VaaS")
268+
269+
if dkp.elliptic_curve:
270+
invalid_value = get_invalid_cloud_ec_value([dkp.elliptic_curve])
271+
if invalid_value:
272+
raise VenafiError(f"Default Elliptic Curve [{invalid_value}] is not supported by VaaS")
273+
274+
275+
def _get_key_types_lowercase(key_types):
276+
lower_kt = []
277+
if key_types:
278+
for kt in key_types:
279+
lower_kt.append(kt.lower())
280+
281+
return lower_kt
254282

255283

256284
def get_invalid_cloud_rsa_key_size_value(rsa_keys):
@@ -264,6 +292,19 @@ def get_invalid_cloud_rsa_key_size_value(rsa_keys):
264292
return None
265293

266294

295+
def get_invalid_cloud_ec_value(elliptic_curves):
296+
"""
297+
298+
:param list[str] elliptic_curves:
299+
:rtype: str
300+
"""
301+
for v in elliptic_curves:
302+
if v not in supported_elliptic_curves:
303+
return v
304+
305+
return None
306+
307+
267308
def get_sans(names):
268309
"""
269310
:param SubjectAltNames names:
@@ -401,20 +442,37 @@ def build_cit_request(ps, ca_details):
401442
else:
402443
request['subjectCValues'] = [ALLOW_ALL]
403444

404-
key_types = dict()
445+
key_types = []
405446
if ps.policy and ps.policy.key_pair and len(ps.policy.key_pair.key_types) > 0:
406-
key_types['keyType'] = ps.policy.key_pair.key_types[0].upper()
407-
else:
408-
key_types['keyType'] = KeyType.RSA.upper()
447+
kt_lowercase = _get_key_types_lowercase(ps.policy.key_pair.key_types)
409448

410-
if ps.policy and ps.policy.key_pair and len(ps.policy.key_pair.rsa_key_sizes) > 0:
411-
key_types['keyLengths'] = ps.policy.key_pair.rsa_key_sizes
412-
elif ps.defaults and ps.defaults.key_pair and ps.defaults.key_pair.rsa_key_size:
413-
key_types['keyLengths'] = [ps.defaults.key_pair.rsa_key_size]
414-
else:
415-
key_types['keyLengths'] = [2048]
449+
if KeyType.RSA in kt_lowercase:
450+
rsa_kt = dict()
451+
rsa_kt['keyType'] = KeyType.RSA.upper()
452+
453+
if ps.policy and ps.policy.key_pair and len(ps.policy.key_pair.rsa_key_sizes) > 0:
454+
rsa_kt['keyLengths'] = ps.policy.key_pair.rsa_key_sizes
455+
elif ps.defaults and ps.defaults.key_pair and ps.defaults.key_pair.rsa_key_size:
456+
rsa_kt['keyLengths'] = [ps.defaults.key_pair.rsa_key_size]
457+
else:
458+
rsa_kt['keyLengths'] = [2048]
459+
460+
key_types.append(rsa_kt)
416461

417-
request['keyTypes'] = [key_types]
462+
if KeyType.ECDSA in kt_lowercase:
463+
ec_kt = dict()
464+
ec_kt['keyType'] = KeyType.ECDSA.upper()
465+
466+
if ps.policy and ps.policy.key_pair and len(ps.policy.key_pair.elliptic_curves) > 0:
467+
ec_kt['keyCurves'] = ps.policy.key_pair.elliptic_curves
468+
elif ps.defaults and ps.defaults.key_pair and ps.defaults.key_pair.elliptic_curve:
469+
ec_kt['keyCurves'] = [ps.defaults.key_pair.elliptic_curve]
470+
else:
471+
ec_kt['keyCurves'] = ['P256']
472+
473+
key_types.append(ec_kt)
474+
475+
request['keyTypes'] = key_types
418476

419477
if ps.policy and ps.policy.key_pair and ps.policy.key_pair.reuse_allowed:
420478
request['keyReuse'] = ps.policy.key_pair.reuse_allowed
@@ -444,12 +502,21 @@ def build_cit_request(ps, ca_details):
444502

445503
r_key = dict()
446504
if ps.defaults and ps.defaults.key_pair:
447-
if ps.defaults.key_pair.key_type:
448-
r_key['type'] = ps.defaults.key_pair.key_type
449-
if ps.defaults.key_pair.rsa_key_size:
450-
r_key['length'] = ps.defaults.key_pair.rsa_key_size
451-
else:
452-
r_key['length'] = 2048
505+
default_kp = ps.defaults.key_pair
506+
if default_kp.key_type:
507+
default_kt = default_kp.key_type.upper()
508+
if default_kt == KeyType.RSA.upper():
509+
if default_kp.rsa_key_size:
510+
r_key['length'] = default_kp.rsa_key_size
511+
else:
512+
r_key['length'] = 2048
513+
elif default_kt == KeyType.ECDSA.upper():
514+
if default_kp.elliptic_curve:
515+
r_key['curve'] = default_kp.elliptic_curve
516+
else:
517+
r_key['curve'] = 'P256'
518+
519+
r_key['type'] = default_kt
453520

454521
if r_key:
455522
r_settings['key'] = r_key

0 commit comments

Comments
 (0)