Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into alex/name-constraint-…
Browse files Browse the repository at this point in the history
…tests
  • Loading branch information
tetsuo-cpp committed Oct 19, 2023
2 parents ca4b2b0 + 762e0b5 commit b863d27
Show file tree
Hide file tree
Showing 6 changed files with 332 additions and 309 deletions.
452 changes: 277 additions & 175 deletions limbo.json

Large diffs are not rendered by default.

79 changes: 4 additions & 75 deletions limbo/assets.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,17 @@
import datetime
import logging
from dataclasses import dataclass
from functools import cache, cached_property
from functools import cached_property
from importlib import resources
from typing import Generic, TypeVar

from cryptography import x509
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric.types import PrivateKeyTypes
from cryptography.x509 import ExtensionType, NameOID, SubjectAlternativeName
from cryptography.x509 import ExtensionType

_EPOCH = datetime.datetime.fromtimestamp(0)
_ONE_THOUSAND_YEARS_OF_TORMENT = _EPOCH + datetime.timedelta(days=365 * 1000)
ONE_THOUSAND_YEARS_OF_TORMENT = _EPOCH + datetime.timedelta(days=365 * 1000)
_ASSETS_PATH = resources.files("limbo._assets")
_ExtensionType = TypeVar("_ExtensionType", bound=ExtensionType)

Expand Down Expand Up @@ -71,73 +70,3 @@ def ext(extension: _ExtensionType, *, critical: bool) -> _Extension[_ExtensionTy
Constructs a new _Extension to pass into certificate builder helpers.
"""
return _Extension(extension, critical)


@cache
def ee_cert(
parent: CertificatePair,
subject_alternative_name: _Extension[SubjectAlternativeName] | None = None,
*,
extra_extension: _Extension | None = None,
) -> CertificatePair:
"""
Produces an end-entity (EE) certificate, signed by the given `parent`'s
key.
"""
# NOTE: Throwaway keys, since we only care that they're distinct.
ee_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)

builder = x509.CertificateBuilder()
builder = builder.subject_name(
x509.Name(
[
x509.NameAttribute(NameOID.COMMON_NAME, "x509-limbo-ee"),
]
)
)
builder = builder.issuer_name(parent.cert.subject)
builder = builder.not_valid_before(_EPOCH)
builder = builder.not_valid_after(_ONE_THOUSAND_YEARS_OF_TORMENT)
builder = builder.serial_number(x509.random_serial_number())
builder = builder.public_key(ee_key.public_key())
builder = builder.add_extension(
x509.SubjectKeyIdentifier.from_public_key(ee_key.public_key()),
critical=False,
)
builder = builder.add_extension(
x509.AuthorityKeyIdentifier.from_issuer_public_key(
parent.key.public_key() # type: ignore[arg-type]
),
critical=False,
)
builder = builder.add_extension(
x509.BasicConstraints(ca=False, path_length=None),
critical=False,
)
builder = builder.add_extension(
x509.KeyUsage(
digital_signature=True,
key_cert_sign=False,
content_commitment=False,
key_encipherment=False,
data_encipherment=False,
key_agreement=False,
crl_sign=False,
encipher_only=False,
decipher_only=False,
),
critical=False,
)
if subject_alternative_name is not None:
builder = builder.add_extension(
subject_alternative_name.ext, subject_alternative_name.critical
)
if extra_extension is not None:
builder = builder.add_extension(extra_extension.ext, extra_extension.critical)

certificate = builder.sign(
private_key=parent.key, # type: ignore[arg-type]
algorithm=hashes.SHA256(),
)

return CertificatePair(certificate, ee_key)
14 changes: 7 additions & 7 deletions limbo/testcases/_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

from limbo.assets import (
_EPOCH,
_ONE_THOUSAND_YEARS_OF_TORMENT,
ONE_THOUSAND_YEARS_OF_TORMENT,
Certificate,
CertificatePair,
_Extension,
Expand Down Expand Up @@ -123,7 +123,7 @@ def root_ca(
subject: x509.Name | None = None,
serial: int | None = None,
not_before: datetime = _EPOCH,
not_after: datetime = _ONE_THOUSAND_YEARS_OF_TORMENT,
not_after: datetime = ONE_THOUSAND_YEARS_OF_TORMENT,
key: PrivateKeyTypes | None = None,
basic_constraints: _Extension[x509.BasicConstraints]
| None = ext(
Expand Down Expand Up @@ -178,7 +178,7 @@ def intermediate_ca(
subject: x509.Name | None = None,
serial: int | None = None,
not_before: datetime = _EPOCH,
not_after: datetime = _ONE_THOUSAND_YEARS_OF_TORMENT,
not_after: datetime = ONE_THOUSAND_YEARS_OF_TORMENT,
key: PrivateKeyTypes | None = None,
basic_constraints: _Extension[x509.BasicConstraints] | Literal[True] | None = True,
key_usage: _Extension[x509.KeyUsage]
Expand Down Expand Up @@ -253,7 +253,7 @@ def leaf_cert(
subject: x509.Name = x509.Name.from_rfc4514_string("CN=x509-limbo-ee"),
serial: int | None = None,
not_before: datetime = _EPOCH,
not_after: datetime = _ONE_THOUSAND_YEARS_OF_TORMENT,
not_after: datetime = ONE_THOUSAND_YEARS_OF_TORMENT,
key: PrivateKeyTypes | None = None,
basic_constraints: _Extension[x509.BasicConstraints] | None = None,
key_usage: _Extension[x509.KeyUsage]
Expand All @@ -271,9 +271,9 @@ def leaf_cert(
),
critical=False,
),
san: _Extension[x509.SubjectAlternativeName] | Literal[True] | None = None,
san: _Extension[x509.SubjectAlternativeName] | Literal[True] | None = True,
aki: _Extension[x509.AuthorityKeyIdentifier] | Literal[True] | None = True,
extra_extension: _Extension[x509.UnrecognizedExtension] | None = None,
extra_extension: _Extension | None = None,
) -> CertificatePair:
"""
Produces an end-entity (EE) certificate, signed by the given `parent`'s
Expand Down Expand Up @@ -349,7 +349,7 @@ def __init__(self, id: str, description: str):
self._extended_key_usage: list[KnownEKUs | OID] | None = None

self._expected_result: str | None = None
self._expected_peer_name: PeerName | None = None
self._expected_peer_name: PeerName | None = PeerName(kind="DNS", value="example.com")
self._expected_peer_names: list[PeerName] | None = None

def features(self, feats: list[Feature]) -> Self:
Expand Down
15 changes: 7 additions & 8 deletions limbo/testcases/pathlen.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from limbo.assets import ee_cert
from limbo.testcases._core import Builder, testcase


Expand All @@ -16,7 +15,7 @@ def ee_with_intermediate_pathlen_0(builder: Builder) -> None:
"""
root = builder.root_ca()
intermediate = builder.intermediate_ca(root, pathlen=0)
leaf = ee_cert(intermediate)
leaf = builder.leaf_cert(intermediate)

builder = builder.server_validation()
builder = (
Expand All @@ -42,7 +41,7 @@ def ee_with_intermediate_pathlen_1(builder: Builder) -> None:

root = builder.root_ca()
intermediate = builder.intermediate_ca(root, pathlen=1)
leaf = ee_cert(intermediate)
leaf = builder.leaf_cert(intermediate)

builder = builder.server_validation()
builder = (
Expand All @@ -68,7 +67,7 @@ def ee_with_intermediate_pathlen_2(builder: Builder) -> None:

root = builder.root_ca()
intermediate = builder.intermediate_ca(root, pathlen=2)
leaf = ee_cert(intermediate)
leaf = builder.leaf_cert(intermediate)

builder = builder.server_validation()
builder = (
Expand Down Expand Up @@ -131,7 +130,7 @@ def intermediate_violates_pathlen_0(builder: Builder) -> None:
root = builder.root_ca()
first_intermediate = builder.intermediate_ca(root, pathlen=0)
second_intermediate = builder.intermediate_ca(first_intermediate, pathlen=0)
leaf = ee_cert(second_intermediate)
leaf = builder.leaf_cert(second_intermediate)

builder = builder.server_validation()
builder = (
Expand Down Expand Up @@ -161,7 +160,7 @@ def intermediate_pathlen_may_increase(builder: Builder) -> None:
root = builder.root_ca()
first_intermediate = builder.intermediate_ca(root, pathlen=1)
second_intermediate = builder.intermediate_ca(first_intermediate, pathlen=2)
leaf = ee_cert(second_intermediate)
leaf = builder.leaf_cert(second_intermediate)

builder = builder.server_validation()
builder = (
Expand Down Expand Up @@ -190,7 +189,7 @@ def intermediate_pathlen_too_long(builder: Builder) -> None:
first_intermediate = builder.intermediate_ca(root, pathlen=1)
second_intermediate = builder.intermediate_ca(first_intermediate, pathlen=0)
third_intermediate = builder.intermediate_ca(second_intermediate, pathlen=0)
leaf = ee_cert(third_intermediate)
leaf = builder.leaf_cert(third_intermediate)

builder = builder.server_validation()
builder = (
Expand Down Expand Up @@ -224,7 +223,7 @@ def self_issued_certs_pathlen(builder: Builder) -> None:
first_intermediate, pathlen=1, subject=first_intermediate.cert.subject
)
third_intermediate = builder.intermediate_ca(second_intermediate, pathlen=0)
leaf = ee_cert(third_intermediate)
leaf = builder.leaf_cert(third_intermediate)

builder = builder.server_validation()
builder.trusted_certs(root).untrusted_intermediates(
Expand Down
Loading

0 comments on commit b863d27

Please sign in to comment.