-
Notifications
You must be signed in to change notification settings - Fork 18
fix: harden JWT and X.509 SVID validation and error handling #375
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,6 +14,8 @@ | |
| under the License. | ||
| """ | ||
|
|
||
| from spiffe.spiffe_id import spiffe_id | ||
|
|
||
| """ | ||
| This module manages X.509 SVID objects. | ||
| """ | ||
|
|
@@ -255,14 +257,32 @@ def load( | |
|
|
||
|
|
||
| def _extract_spiffe_id(cert: Certificate) -> SpiffeId: | ||
| ext = cert.extensions.get_extension_for_oid(x509.ExtensionOID.SUBJECT_ALTERNATIVE_NAME) | ||
| if isinstance(ext.value, x509.SubjectAlternativeName): | ||
| sans = ext.value.get_values_for_type(x509.UniformResourceIdentifier) | ||
| if len(sans) == 0: | ||
| try: | ||
| ext = cert.extensions.get_extension_for_oid(x509.ExtensionOID.SUBJECT_ALTERNATIVE_NAME) | ||
| except x509.ExtensionNotFound: | ||
| raise InvalidLeafCertificateError( | ||
| 'Certificate does not contain a SubjectAlternativeName extension' | ||
| ) | ||
|
|
||
| if not isinstance(ext.value, x509.SubjectAlternativeName): | ||
| raise InvalidLeafCertificateError( | ||
| 'Certificate does not contain a SPIFFE ID in the URI SAN' | ||
| ) | ||
|
|
||
| uri_sans = ext.value.get_values_for_type(x509.UniformResourceIdentifier) | ||
| spiffe_uris = [uri for uri in uri_sans if uri.startswith(spiffe_id.SCHEME_PREFIX)] | ||
|
|
||
| if len(spiffe_uris) == 0: | ||
| raise InvalidLeafCertificateError( | ||
| 'Certificate does not contain a SPIFFE ID in the URI SAN' | ||
| ) | ||
| return SpiffeId(sans[0]) | ||
|
|
||
| if len(spiffe_uris) > 1: | ||
| raise InvalidLeafCertificateError( | ||
| 'Certificate contains multiple SPIFFE IDs in the URI SAN' | ||
| ) | ||
|
||
|
|
||
| return SpiffeId(spiffe_uris[0]) | ||
|
||
|
|
||
|
|
||
| def _validate_chain(cert_chain: List[Certificate]) -> None: | ||
|
|
@@ -274,13 +294,23 @@ def _validate_chain(cert_chain: List[Certificate]) -> None: | |
|
|
||
|
|
||
| def _validate_leaf_certificate(leaf: Certificate) -> None: | ||
| basic_constraints = leaf.extensions.get_extension_for_oid( | ||
| x509.ExtensionOID.BASIC_CONSTRAINTS | ||
| ).value | ||
| try: | ||
| basic_constraints = leaf.extensions.get_extension_for_oid( | ||
| x509.ExtensionOID.BASIC_CONSTRAINTS | ||
| ).value | ||
| except x509.ExtensionNotFound: | ||
| raise InvalidLeafCertificateError( | ||
| 'Leaf certificate must have BasicConstraints extension' | ||
| ) | ||
|
|
||
| if isinstance(basic_constraints, x509.BasicConstraints) and basic_constraints.ca: | ||
| raise InvalidLeafCertificateError('Leaf certificate must not have CA flag set to true') | ||
|
|
||
| key_usage = leaf.extensions.get_extension_for_oid(x509.ExtensionOID.KEY_USAGE).value | ||
| try: | ||
| key_usage = leaf.extensions.get_extension_for_oid(x509.ExtensionOID.KEY_USAGE).value | ||
| except x509.ExtensionNotFound: | ||
| raise InvalidLeafCertificateError('Leaf certificate must have KeyUsage extension') | ||
|
|
||
| if isinstance(key_usage, x509.KeyUsage) and not key_usage.digital_signature: | ||
| raise InvalidLeafCertificateError( | ||
| 'Leaf certificate must have \'digitalSignature\' as key usage' | ||
|
|
@@ -296,14 +326,27 @@ def _validate_leaf_certificate(leaf: Certificate) -> None: | |
|
|
||
|
|
||
| def _validate_intermediate_certificate(cert: Certificate) -> None: | ||
| basic_constraints = cert.extensions.get_extension_for_oid( | ||
| x509.ExtensionOID.BASIC_CONSTRAINTS | ||
| ).value | ||
| try: | ||
| basic_constraints = cert.extensions.get_extension_for_oid( | ||
| x509.ExtensionOID.BASIC_CONSTRAINTS | ||
| ).value | ||
| except x509.ExtensionNotFound: | ||
| raise InvalidIntermediateCertificateError( | ||
| 'Intermediate certificate must have BasicConstraints extension' | ||
| ) | ||
|
|
||
| if isinstance(basic_constraints, x509.BasicConstraints) and not basic_constraints.ca: | ||
| raise InvalidIntermediateCertificateError( | ||
| 'Signing certificate must have CA flag set to true' | ||
| ) | ||
| key_usage = cert.extensions.get_extension_for_oid(x509.ExtensionOID.KEY_USAGE).value | ||
|
|
||
| try: | ||
| key_usage = cert.extensions.get_extension_for_oid(x509.ExtensionOID.KEY_USAGE).value | ||
| except x509.ExtensionNotFound: | ||
| raise InvalidIntermediateCertificateError( | ||
| 'Intermediate certificate must have KeyUsage extension' | ||
| ) | ||
|
|
||
| if isinstance(key_usage, x509.KeyUsage) and not key_usage.key_cert_sign: | ||
| raise InvalidIntermediateCertificateError( | ||
| 'Signing certificate must have \'keyCertSign\' as key usage' | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't seem like we have test coverage for this new validation. I think that it would be great to have it covered by tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added test coverage.