Skip to content

Commit

Permalink
STNDS-462 (#29)
Browse files Browse the repository at this point in the history
* Switch all uses of magic strings to new KeyUsage bit name class

* STNDS-462

* Fix build
  • Loading branch information
CBonnell authored Apr 10, 2024
1 parent 779d968 commit e569e57
Show file tree
Hide file tree
Showing 50 changed files with 429 additions and 65 deletions.
9 changes: 5 additions & 4 deletions pkilint/cabf/cabf_ca.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from pkilint import validation
from pkilint.itu import bitstring
from pkilint.pkix.certificate.certificate_extension import KeyUsageBitName


# BR 7.1.2.10.7
Expand All @@ -23,7 +24,7 @@ class CaKeyUsageValidator(validation.Validator):

_PROHIBITED_KUS = {
str(n) for n in rfc5280.KeyUsage.namedValues
} - {'digitalSignature', 'keyCertSign', 'cRLSign'}
} - {KeyUsageBitName.DIGITAL_SIGNATURE, KeyUsageBitName.KEY_CERT_SIGN, KeyUsageBitName.CRL_SIGN}

def __init__(self):
super().__init__(
Expand All @@ -36,12 +37,12 @@ def __init__(self):
)

def validate(self, node):
if not bitstring.has_named_bit(node, 'keyCertSign'):
if not bitstring.has_named_bit(node, KeyUsageBitName.KEY_CERT_SIGN):
raise validation.ValidationFindingEncountered(
self.VALIDATION_CA_CERT_REQUIRED_BIT_MISSING,
'keyCertSign not asserted'
)
if not bitstring.has_named_bit(node, 'cRLSign'):
if not bitstring.has_named_bit(node, KeyUsageBitName.CRL_SIGN):
raise validation.ValidationFindingEncountered(
self.VALIDATION_CA_CERT_REQUIRED_BIT_MISSING,
'cRLSign not asserted'
Expand All @@ -55,7 +56,7 @@ def validate(self, node):
f'Prohibited KUs present: {prohibited_kus_str}'
)

if not bitstring.has_named_bit(node, 'digitalSignature'):
if not bitstring.has_named_bit(node, KeyUsageBitName.DIGITAL_SIGNATURE):
raise validation.ValidationFindingEncountered(self.VALIDATION_CA_CERT_NO_DIG_SIG)


Expand Down
6 changes: 3 additions & 3 deletions pkilint/cabf/serverauth/serverauth_ocsp.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from pkilint import validation, common
from pkilint.itu import bitstring
from pkilint.pkix import Rfc2119Word

from pkilint.pkix.certificate.certificate_extension import KeyUsageBitName

_CODE_CLASSIFIER = 'cabf.serverauth.ocsp_responder'

Expand All @@ -24,14 +24,14 @@ class OcspResponderKeyUsageValidator(validation.Validator):

_PROHIBITED_KUS = {
str(n) for n in rfc5280.KeyUsage.namedValues
} - {'digitalSignature'}
} - {KeyUsageBitName.DIGITAL_SIGNATURE}

def __init__(self):
super().__init__(validations=[self.VALIDATION_DIGSIG_MISSING, self.VALIDATION_PROHIBITED_KU_PRESENT],
pdu_class=rfc5280.KeyUsage)

def validate(self, node):
if not bitstring.has_named_bit(node, 'digitalSignature'):
if not bitstring.has_named_bit(node, KeyUsageBitName.DIGITAL_SIGNATURE):
raise validation.ValidationFindingEncountered(self.VALIDATION_DIGSIG_MISSING)

prohibited_kus_asserted = sorted((k for k in self._PROHIBITED_KUS if bitstring.has_named_bit(node, k)))
Expand Down
15 changes: 8 additions & 7 deletions pkilint/cabf/serverauth/serverauth_subscriber.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from pkilint.common.organization_id import ParsedOrganizationIdentifier
from pkilint.itu import x520_name, bitstring
from pkilint.pkix import Rfc2119Word, general_name, time
from pkilint.pkix.certificate.certificate_extension import KeyUsageBitName


def _parse_organization_identifier_extension(
Expand Down Expand Up @@ -265,13 +266,13 @@ class SubscriberKeyUsageValidator(validation.Validator):

_SPKI_OID_TO_KU_ALLOWANCES_MAPPING = {
rfc5480.rsaEncryption: {
'digitalSignature': Rfc2119Word.SHOULD,
'keyEncipherment': Rfc2119Word.MAY,
'dataEncipherment': Rfc2119Word.SHOULD_NOT,
KeyUsageBitName.DIGITAL_SIGNATURE: Rfc2119Word.SHOULD,
KeyUsageBitName.KEY_ENCIPHERMENT: Rfc2119Word.MAY,
KeyUsageBitName.DATA_ENCIPHERMENT: Rfc2119Word.SHOULD_NOT,
},
rfc5480.id_ecPublicKey: {
'digitalSignature': Rfc2119Word.MUST,
'keyAgreement': Rfc2119Word.SHOULD_NOT,
KeyUsageBitName.DIGITAL_SIGNATURE: Rfc2119Word.MUST,
KeyUsageBitName.KEY_AGREEMENT: Rfc2119Word.SHOULD_NOT,
},
}

Expand Down Expand Up @@ -321,8 +322,8 @@ def validate(self, node):
))

if spki_alg_oid == rfc5480.rsaEncryption and (
bitstring.has_named_bit(node, 'digitalSignature') and
bitstring.has_named_bit(node, 'keyEncipherment')):
bitstring.has_named_bit(node, KeyUsageBitName.DIGITAL_SIGNATURE) and
bitstring.has_named_bit(node, KeyUsageBitName.KEY_ENCIPHERMENT)):
warning_findings.append(
validation.ValidationFindingDescription(self.VALIDATION_RSA_DIGSIG_AND_KEYENCIPHERMENT_PRESENT, None)
)
Expand Down
61 changes: 25 additions & 36 deletions pkilint/cabf/smime/smime_extension.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
from pkilint.cabf.smime.smime_constants import Generation, ValidationLevel
from pkilint.cabf.smime.smime_name import get_email_addresses_from_san
from pkilint.iso import lei
from pkilint.itu import bitstring
from pkilint.pkix import extension
from pkilint.pkix.certificate.certificate_extension import KeyUsageBitName


class CertificatePoliciesPresenceValidator(extension.ExtensionPresenceValidator):
Expand Down Expand Up @@ -277,25 +279,6 @@ def validate(self, node):
return validation.ValidationResult(self, node, findings)


def _has_bit(node, bit_name):
bit = rfc5280.KeyUsage.namedValues[bit_name]
return len(node.pdu) > bit and node.pdu[bit] != 0


def _get_prohibited_kus(node, allowed_kus):
prohibited_kus = (
set(map(str, rfc5280.KeyUsage.namedValues)).difference(
allowed_kus
)
)

return [
pk
for pk in prohibited_kus
if _has_bit(node, pk)
]


class AllowedKeyUsageValidator(validation.Validator):
VALIDATION_UNKNOWN_CERT_TYPE = validation.ValidationFinding(
validation.ValidationFindingSeverity.ERROR,
Expand All @@ -317,6 +300,8 @@ class AllowedKeyUsageValidator(validation.Validator):
'cabf.smime.unsupported_public_key_type'
)

_ALL_KUS = {str(n) for n in rfc5280.KeyUsage.namedValues}

def __init__(self, generation):
super().__init__(
validations=[
Expand All @@ -330,37 +315,41 @@ def __init__(self, generation):

self._generation = generation

@classmethod
def _get_prohibited_kus(cls, node, allowed_kus):
return {
pk
for pk in cls._ALL_KUS - allowed_kus
if bitstring.has_named_bit(node, pk)
}

def validate(self, node):
spki_alg_oid = node.navigate(
':certificate.tbsCertificate.subjectPublicKeyInfo.algorithm.algorithm'
).pdu

DS = 'digitalSignature'
NR = 'nonRepudiation'
DE = 'dataEncipherment'
KE = 'keyEncipherment'
KA = 'keyAgreement'
EO = 'encipherOnly'
DO = 'decipherOnly'

allowed_kus = {DS}
is_signing_cert = _has_bit(node, DS)
allowed_kus = {KeyUsageBitName.DIGITAL_SIGNATURE}
is_signing_cert = bitstring.has_named_bit(node, KeyUsageBitName.DIGITAL_SIGNATURE)

if is_signing_cert:
allowed_kus.add(NR)
allowed_kus.add(KeyUsageBitName.NON_REPUDIATION)

if spki_alg_oid == rfc3279.rsaEncryption:
allowed_kus.add(KE)
allowed_kus.add(KeyUsageBitName.KEY_ENCIPHERMENT)

is_key_mgmt_cert = _has_bit(node, KE)
is_key_mgmt_cert = bitstring.has_named_bit(node, KeyUsageBitName.KEY_ENCIPHERMENT)

if is_key_mgmt_cert and self._generation != Generation.STRICT:
allowed_kus.add(DE)
allowed_kus.add(KeyUsageBitName.DATA_ENCIPHERMENT)
elif spki_alg_oid == rfc5480.id_ecPublicKey:
is_key_mgmt_cert = _has_bit(node, KA)
is_key_mgmt_cert = bitstring.has_named_bit(node, KeyUsageBitName.KEY_AGREEMENT)

if is_key_mgmt_cert:
allowed_kus.update({EO, DO, KA})
allowed_kus.update({
KeyUsageBitName.ENCIPHER_ONLY,
KeyUsageBitName.DECIPHER_ONLY,
KeyUsageBitName.KEY_AGREEMENT,
})
elif spki_alg_oid in {rfc8410.id_Ed448, rfc8410.id_Ed25519}:
is_key_mgmt_cert = False
else:
Expand All @@ -369,7 +358,7 @@ def validate(self, node):
if not is_signing_cert and not is_key_mgmt_cert:
raise validation.ValidationFindingEncountered(self.VALIDATION_UNKNOWN_CERT_TYPE)

prohibited_kus = _get_prohibited_kus(node, allowed_kus)
prohibited_kus = self._get_prohibited_kus(node, allowed_kus)

if len(prohibited_kus) > 0:
ku_str = ', '.join(sorted(prohibited_kus))
Expand Down
15 changes: 10 additions & 5 deletions pkilint/common/__init__.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
from typing import Callable, Mapping, Optional, NamedTuple
from typing import Callable, Mapping, Optional

from pyasn1.type import univ
from pyasn1_alt_modules import rfc5280, rfc6962, rfc6960
from pyasn1_alt_modules import rfc5280, rfc6962, rfc6960, rfc3739

from pkilint import validation, document, pkix, oid
from pkilint import validation, document, pkix
from pkilint.cabf.asn1 import ev_guidelines
from pkilint.itu import x520_name
from pkilint.pkix import Rfc2119Word

OID_TO_CODE_NAME = {
# EKU
# EKUs
rfc5280.id_kp_codeSigning: 'codesigning',
rfc5280.id_kp_emailProtection: 'emailprotection',
rfc5280.id_kp_timeStamping: 'timestamping',
Expand All @@ -19,7 +19,7 @@
rfc5280.id_kp_serverAuth: 'serverauth',
rfc5280.id_kp_clientAuth: 'clientauth',

# extension
# extensions
rfc5280.id_ce_authorityKeyIdentifier: 'authority_key_identifier',
rfc5280.id_ce_basicConstraints: 'basic_constraints',
rfc5280.id_ce_certificatePolicies: 'certificate_policies',
Expand All @@ -33,6 +33,11 @@
rfc5280.id_ce_subjectAltName: 'subject_altname',
rfc6962.id_ce_criticalPoison: 'precert_poison',
rfc6960.id_pkix_ocsp_nocheck: 'ocsp_nocheck',
rfc3739.id_pe_qcStatements: 'qc_statements',
rfc5280.id_ce_policyMappings: 'policy_mappings',
rfc5280.id_ce_policyConstraints: 'policy_constraints',
rfc5280.id_ce_inhibitAnyPolicy: 'inhibit_any_policy',


# AIA access methods
rfc5280.id_ad_ocsp: 'ocsp',
Expand Down
2 changes: 2 additions & 0 deletions pkilint/etsi/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,8 @@ def create_validators(certificate_type: CertificateType) -> List[validation.Vali
en_319_412_2.IssuerAlternativeNameCriticalityValidator(),
en_319_412_2.ExtendedKeyUsageCriticalityValidator(),
en_319_412_2.CRLDistributionPointsCriticalityValidator(),
en_319_412_2.NaturalPersonExtensionIdentifierAllowanceValidator(certificate_type),
en_319_412_2.KeyUsageValueValidator(is_content_commitment_type=False),
qc_statements_validator_container
]

Expand Down
Loading

0 comments on commit e569e57

Please sign in to comment.