1.4.0
    - Add cert_info --version diagnostics on stderr: library version, Python
      version and invoked binary path, without requiring a certificate target.
    - BREAKING: rename cert_info flags to --discover-certbot,
      --certbot-config-directory and --certbot-managed. The Certbot application
      manages this layout; Let's Encrypt is the certificate authority.
      Remove the former letsencrypt flag spellings and update CLI guidance.
1.3.2
    - Support local Let's Encrypt discovery for fetched HTTPS certificates and
      print the peer PEM to stdout. Refresh README CLI and cache guidance.
1.3.1
    - Add bad-payload validation and cross-object RSA/EC SPKI regression tests
      for native and OpenSSL backends.
    - Document KeyData.modulus_md5 and parse_key's modulus field as deprecated;
      retain compatibility and direct RSA/EC relationships to spki_sha256.
    - Keep audit/handoff notes local and exclude audits/ from source control.
    - Update GitHub Actions checkout/setup-python/upload-artifact releases.
    - Deprecate modulus_md5_key/csr/cert with caller-directed warnings and
      SPKI SHA-256 migration guidance; existing results remain unchanged.
    - Record remaining SPKI relationship/legacy-field migration follow-ups.
    - Fix the discovery cache precedence test for Python 3.7 mock call tuples.
    - Make local cert_info ARI checks opt-in with --check-ari.
    - Add explicit Certbot discovery, managed filesystem context, and private
      versioned per-root metadata caching with CLI/environment controls.
    - Report identical certificate copies, domain matches and inferred account
      relationships; all mode also compares managed paths and public keys.
1.3.0
    - yanked; mis-release without all commits.
1.2.2
    - Add identifiers.parse_cert_identifiers and parse_csr_identifiers with
      typed DNS/IP SAN values, canonical IP strings and native/OpenSSL parity.
      SANs override CN; legacy DNS CN fallback applies only when SAN is absent.
      Keep the existing flat-name APIs unchanged. OpenSSL calls are bounded,
      cleaned up, and do not include raw diagnostic data in exceptions.
    - Add a typed, JSON-compatible letsencrypt_info.profiles policy snapshot
      with source provenance, duration units, retired profiles and announced
      classic-profile validity/reuse changes. It is advisory metadata; server
      advertisements and actual certificate/ACME timestamps remain authoritative.
1.2.1
    - Strengthen CertificateData: issuer, subject, validity dates and SHA-1
      fingerprint are required values on both parsing backends. Parsing errors
      raise; metadata unavailable for unsupported keys remains optional.
1.2.0
    - Implement account_key__verify's OpenSSL fallback using psutil.Popen.
      Return None on success; fallback failures raise OpenSslError_InvalidSignature
      (an OpenSslError subclass). Native InvalidSignature behavior is preserved.
    - Fix EC fallback signing to honor standardize_signature: True returns
      fixed-width r||s, False/None returns DER. Existing fallback callers needing
      DER must explicitly pass False. SHA-256 remains unchanged on both backends.
    - Organize Let's Encrypt metadata under letsencrypt_info: certificates.py,
      rate_limits.py and shared types.py. The namespace imports neither dataset
      eagerly; the bundled PEM directory stays at its established location.
    - BREAKING: replace LIMITS with versioned rate-policy schema 2. Import
      cert_utils.letsencrypt_info.rate_limits.RATE_LIMITS for the CA-independent
      catalogue. Old schema keys and module-level metadata imports are removed;
      see docs/rate-limits.md for migration.
    - Update production policy from the 2026-08-05 source: separate scopes,
      refill/burst values, renewal exemptions, failure guards and profile
      constraints. See docs/rate-limits.md for migration and throttling caveats.
    - Refresh the bundled Let's Encrypt CA archive (CERT_CAS_VERSION = 5):
      add YE/YR roots, their cross-signs, the renewed X2 cross-sign and YE/YR
      intermediates. Mark YE3/YR3 as backups and preserve retired certificates
      under letsencrypt-certs/deprecated with corrected metadata.
    - Add pending YE/YR roots after established X2/X1 root preferences; they
      are not yet trusted by major root stores. Preserve the original X2
      cross-sign under its existing key in CERT_CAS_DEPRECATED; the renewed
      certificate uses isrg_root_x2_cross_2025.
    - Remove setup.py; build with the pyproject.toml setuptools backend.
    - Correct CLI argv handling and public typing contracts.
    - Return structured certificate/CSR/key result types to type checkers.
    - Fix OpenSSL EC checks and CSR generation for paths containing spaces.
    - Align chain validation purpose; add validation_time, purpose, and
      server_hostname keyword arguments. Defaults still validate at current time.
    - Align chain ordering across backends: ordering is distinct from trust,
      expiry, signature and purpose validation; use ensure_chain for validation.
    - Invalid CSR signatures now raise OpenSslError_InvalidCSR consistently.
    - Added Python3.14 to test and support matrix

1.1.1
    - fix "display_name" and "alternates" of letsencrypt staging cross-sign

1.1.0
    - Minor typing updates

    Backwards Incompatible Changes::

    - expired letsencrypt certs are now in a /deprecated subdirectory; payloads reflect this
    - CERT_CA_PAYLOAD, used by CERT_CAS_DATA["compatability"]
        was: Dict[str, str] (name: version)
        now: Dict[str, Tuple[str, Optional[str], Optional[str]]] (name: min, max, note)
    
    - CERT_CAS_DATA: Expired certs have been moved to: CERT_CAS_DEPRECATED
    - _CERT_CAS_ORDER: Expired cert names have been moved to: _CERT_CAS_DEPRECATED_ORDER
    
    Why?
    
    * the compatability matrix needed to split out versions for notes for future comparison. more standardization is needed.
    * the compatability matrix does not account for a max_version, which can happen if a cert is removed from a trust store
    * deprecated certs are maintained for research and historical purposes
    
1.0.6
    * the following functions now accept kwarg `ipv6_require_compressed`, a bool.
      if True (default False), ipv6 values must be compressed.
            - domains_from_list
            - domains_from_string
            - validate_domains
     The initial behavior of LetsEncrypt will be to require compressed ipv6
     addresses, though this may change in the future. The LetsEncrypt API will
     write ipv6 address strings in the compressed format; and the data in
     certificates will be raw bytes.
    * new function `validate_ipv6_address`

1.0.5
    * fixed bug in domain regex that excluded single letter subdomains    
    * added empty __init__.py files for setuptools to be happy
1.0.4
    The following functions now accept new kwargs:
        * kwargs:
            allow_hostname: bool = True
            allow_ipv4: bool = False
            allow_ipv6: bool = False
        * functions
            - domains_from_list
            - domains_from_string
            - validate_domains
    * new functions
        utils.identify_san_type
    * updated repo to not allow admins to bypass rules
    
1.0.3
    * exception did not properly interpolate variable

1.0.2
    * adjustemnts to josepy
      added "CERT_UTILS_FORCE_JOSEPY" env var

1.0.1
    * logging cleanup
    * pinned "josepy<2" in advance of breaking changes;
      no planned changes should affect this library
    * updated pre-commit configuration
        - upgraged black to psf distribution
        - added flake8

1.0.0
    * new_account_key supports LetsEncrypt updates to EC
    * ALLOWED_CURVES_ECDSA is now a list of strings
    * new_ec_key named argument is now curve(str)
    * functions now require KeyTechnologyEnum, not KeyTechnology for key_technology_id
    * added account_key__verify
    * extended account_key__sign to accept `standardize_signature`; default True
      for converting the EC signature to the encoding ACME requires
    * corrected use of `secp256k1` to `secp256r1`
    * `key_technology` concept of "RSA" and "EC" has been renamed to `key_technology_basic`
    * `key_technology` concept is now a tuple of `(key_technology_basic, (data, ))`
      For a RSA, the payload is:
            ("rsa", (rsa_bits,))
      For an EC, the payload is:
            ("ec", (nist_curve_name,))
    * validate_domains now accepts a wildcard

0.2.0
    * replaced pyopenssl with cryptography.
      pyopenssl was originally used because certbot required it and this package
      was originally developed to troubleshoot certbot installations;
      however certbot uses cryptography, so we can consider that to be available
      and it is the officially preferred interface by both projects and the psf.
    * split the package into multiple files
      this is for internal use and organization is subject to change.
      please access the main namespace.
    * dropped Python3.6
      this package requires cryptography>=42.0.0, specifically for chain verification
      cryptography dropped Python3.6 in v41.0.0

0.1.9
    pulled ari serial_no decoder into a separate unction
    parsing akid defensively against edge case variants:
        in web pki it is almost always "keyid:"
        however the rfc allows for "uri:"+"serial:", 
        either in addition to keyid or replacing it
    this should be the final release in the 0.1.x branch;
    work has been started for 0.2.0, which will migrate away from openssl

0.1.8
    added cert_info cli tool

0.1.7
    ARI support
        * ari_construct_identifier()
    added `serial` to parse_cert dicts
    testing on py13

0.1.6
    updated LetsEncrypt data

0.1.5 [deleted from PyPi]
    updated typing and tests
    updated LetsEncrypt data
    
0.1.4
    updated typing for dependencies

0.1.3
    new mypy version caught an issue

0.1.2
    docs improvements
    raise a new `FallbackError_FilepathRequired` exception when missing a
        required fallback filepath

0.1.1
    minor formatting
    Conditional Imports
        imports are tried "one at a time"; not "all or nothing".
        functions that use imports should test for all necessary options
    new extended tests for lacking specific libraries
    tests now monitor logs to ensure fallback behavior is triggered correctly

0.1.0
    initial release
    forked from peter_sslers

CLI follow-up (unreleased)
    - Add offline CLI coverage; fix issuer parsing, missing peer data,
      module dispatch, ARI HTTP errors and renewal URL joining.
    - Move the historical OpenSSL MD5 reference into project documentation.

HTTP configuration (unreleased)
    - Add connect/read timeout defaults (5/30 seconds), CERT_UTILS_TIMEOUT and
      --timeout CONNECT,READ overrides. Close CLI-owned sessions reliably.
    - Document profile-dependent CN behavior and intentional peer-socket probes.

CI compatibility (unreleased)
    - Select pyproject.toml explicitly when invoking tox, avoiding the
      setup.cfg discovery failure in tox 4.30.x on Python 3.9.

Python 3.7 test compatibility (unreleased)
    - Access mock calls as (args, kwargs) tuples; the .args/.kwargs convenience
      properties are unavailable on Python 3.7.
    - Tie the tox 4.30.3 configuration workaround to Python 3.9 support.
