From 99bd7a552207c9fc8dcb0ed84529c210bfc258c4 Mon Sep 17 00:00:00 2001 From: Min RK Date: Thu, 27 Mar 2025 12:37:10 +0100 Subject: [PATCH 1/4] test with default SSL configuration 3.13 fails with Missing Authority Key Identifier due to new default strictness --- .github/workflows/ci.yml | 14 ++++++++++++-- certipy/test/test_certipy.py | 22 +++++++++++++++------- pyproject.toml | 2 +- 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 55ef7ee..5bc00fd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,14 +14,24 @@ concurrency: jobs: test: - runs-on: ubuntu-latest + runs-on: ${{ matrix.os || 'ubuntu-latest' }} + strategy: + fail-fast: false + matrix: + python: + - "3.8" + - "3.12" + - "3.x" + include: + - os: ubuntu-22.04 + python: "3.7" steps: - uses: actions/checkout@v4 - name: setup uses: actions/setup-python@v5 with: - python-version: '3.x' + python-version: ${{ matrix.python }} - name: install run: | python -m pip install --upgrade pip diff --git a/certipy/test/test_certipy.py b/certipy/test/test_certipy.py index 21a9763..355bbcb 100644 --- a/certipy/test/test_certipy.py +++ b/certipy/test/test_certipy.py @@ -12,13 +12,12 @@ import os import pytest -import requests import socket import ssl +from urllib.request import urlopen, URLError from contextlib import closing, contextmanager from datetime import datetime, timedelta, timezone from flask import Flask -from requests.exceptions import SSLError from tempfile import TemporaryDirectory from threading import Thread from werkzeug.serving import make_server @@ -61,7 +60,7 @@ def tls_server(certfile: str, keyfile: str, host: str = "localhost", port: int = if port == 0: port = find_free_port() - ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) + ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) ssl_context.load_cert_chain(certfile, keyfile) server = make_server( host, port, make_flask_app(), ssl_context=ssl_context, threaded=True @@ -373,10 +372,19 @@ def test_certs(): ) as server: # Execute/Verify url = f"https://{server.host}:{server.port}" - # Fails without specifying a CA for verification - with pytest.raises(SSLError): - requests.get(url) + with pytest.raises(URLError, match="SSL"): + with urlopen(url): + pass + + ssl_context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH, cafile=ca_record["files"]["cert"]) + ssl_context.verify_mode = ssl.CERT_REQUIRED + ssl_context.load_default_certs() + ssl_context.load_cert_chain(ca_record["files"]["cert"], ca_record["files"]["key"]) + # currently required to pass on 3.13 + # if hasattr(ssl, "VERIFY_X509_STRICT"): + # ssl_context.verify_flags &= ~ssl.VERIFY_X509_STRICT # Succeeds when supplying the CA cert - requests.get(url, verify=ca_record["files"]["cert"]) + with urlopen(url, context=ssl_context): + pass diff --git a/pyproject.toml b/pyproject.toml index 3bbebdd..49e2966 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -41,7 +41,7 @@ requires-python = ">=3.7" dependencies = ["cryptography"] [project.optional-dependencies] -dev = ["pytest", "flask", "build", "requests", "pre-commit", "ruff", "bump-my-version"] +dev = ["pytest", "flask", "build", "pre-commit", "ruff", "bump-my-version"] [tool.setuptools.dynamic] version = {attr = "certipy.version.__version__"} From 80e99b07b2001ea60f624e9c83e9575bb5b1ac16 Mon Sep 17 00:00:00 2001 From: Min RK Date: Thu, 27 Mar 2025 12:46:14 +0100 Subject: [PATCH 2/4] can't support Python 3.7 if we require setuptools-scm 8 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 49e2966..1524146 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,7 +10,7 @@ # SPDX-License-Identifier: BSD-3-Clause ############################################################################### [build-system] -requires = ["setuptools>=64", "setuptools_scm>=8"] +requires = ["setuptools>=64", "setuptools_scm>=7"] build-backend = "setuptools.build_meta" [project] From c27542cad56b3fe8325655879256f049d0a3ed9f Mon Sep 17 00:00:00 2001 From: Min RK Date: Thu, 27 Mar 2025 12:49:54 +0100 Subject: [PATCH 3/4] return flask app --- certipy/test/test_certipy.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/certipy/test/test_certipy.py b/certipy/test/test_certipy.py index 355bbcb..a5bbf70 100644 --- a/certipy/test/test_certipy.py +++ b/certipy/test/test_certipy.py @@ -53,6 +53,8 @@ def make_flask_app(): @app.route("/") def working(): return "working" + + return app @contextmanager From 3107a414712896a030f48ef9e0e0bdc0f92dd636 Mon Sep 17 00:00:00 2001 From: Min RK Date: Thu, 27 Mar 2025 13:01:44 +0100 Subject: [PATCH 4/4] add AuthorityKeyIdentifier extension required for default ssl.VERIFY_X509_STRICT in Python 3.13 --- certipy/certipy.py | 4 ++++ certipy/test/test_certipy.py | 3 --- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/certipy/certipy.py b/certipy/certipy.py index 2ac4173..1ae76d6 100644 --- a/certipy/certipy.py +++ b/certipy/certipy.py @@ -922,6 +922,10 @@ def create_signed_pair( cacert = ca_bundle.cert.load() cakey = ca_bundle.key.load() + extensions.append( + (x509.AuthorityKeyIdentifier.from_issuer_public_key(cacert.public_key()), False) + ) + now = datetime.now(timezone.utc) eol = now + timedelta(days=years * 365) cert = self.sign( diff --git a/certipy/test/test_certipy.py b/certipy/test/test_certipy.py index a5bbf70..f5cb744 100644 --- a/certipy/test/test_certipy.py +++ b/certipy/test/test_certipy.py @@ -383,9 +383,6 @@ def test_certs(): ssl_context.verify_mode = ssl.CERT_REQUIRED ssl_context.load_default_certs() ssl_context.load_cert_chain(ca_record["files"]["cert"], ca_record["files"]["key"]) - # currently required to pass on 3.13 - # if hasattr(ssl, "VERIFY_X509_STRICT"): - # ssl_context.verify_flags &= ~ssl.VERIFY_X509_STRICT # Succeeds when supplying the CA cert with urlopen(url, context=ssl_context):