Skip to content

feat(pki): add IP address SAN support to ACME certificate issuance#5771

Merged
saifsmailbox98 merged 6 commits intomainfrom
saif/pki-145-pki-acme-error-ip-address-sans
Mar 21, 2026
Merged

feat(pki): add IP address SAN support to ACME certificate issuance#5771
saifsmailbox98 merged 6 commits intomainfrom
saif/pki-145-pki-acme-error-ip-address-sans

Conversation

@saifsmailbox98
Copy link
Copy Markdown
Contributor

Context

ACME certificate issuance rejected IP address identifiers with "Only DNS identifiers are supported."
The underlying CA infrastructure already supported IP SANs - only the ACME layer was blocking them.

Fixes #5550

Steps to verify the change

Type

  • Fix
  • Feature
  • Improvement
  • Breaking
  • Docs
  • Chore

Checklist

  • Title follows the conventional commit format: type(scope): short description (scope is optional, e.g., fix: prevent crash on sync or fix(api): handle null response).
  • Tested locally
  • Updated docs (if needed)
  • Updated CLAUDE.md files (if needed)
  • Read the contributing guide

@linear
Copy link
Copy Markdown

linear bot commented Mar 20, 2026

@maidul98
Copy link
Copy Markdown
Collaborator

maidul98 commented Mar 20, 2026

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 20, 2026

Greptile Summary

This PR extends Infisical's ACME certificate issuance to support IP address identifiers (RFC 8738), unblocking the use case where the underlying CA already supports IP SANs but the ACME layer was rejecting them. The changes span identifier validation, challenge type selection (HTTP-01 only for IP), CSR matching, and IPv6 URL construction.

Key changes:

  • Adds AcmeIdentifierType.IP = "ip" to the schema enum.
  • Validates IP identifiers via isValidIp and conditionally blocks private IPs when ownership verification is enabled.
  • Restricts IP identifiers to HTTP-01 challenges only (DNS-01 not applicable per RFC 8738).
  • Updates CSR finalization to match SANs and CN against both DNS and IP authorized identifiers using "type:value" pair sets.
  • Adds IPv6 bracket wrapping for URL construction in HTTP-01 challenge validation.

Issues found:

  • IPv6 support is broken when ownership verification is enabled: isPrivateIp in ipRange.ts only defines IPv4 BlockList ranges. For IPv6 addresses, BlockList.check(ip) defaults to type 'ipv4', which throws for non-IPv4 strings. This exception surfaces as a plain BadRequestError for all IPv6 identifiers when skipDnsOwnershipVerification=false, not a proper ACME error. IPv6 private/loopback addresses (e.g., ::1, fc00::/7, fe80::/10) are also completely unguarded.
  • IPv6 Host header missing brackets: The HTTP Host header during HTTP-01 challenge validation uses the raw identifier value (e.g., ::1) without brackets, violating RFC 7230 §5.4. The URL construction was correctly fixed but the header was not.
  • The private-IP validation inside the authorization-creation map callback is a duplicate of the pre-transaction loop and is unreachable dead code.

Confidence Score: 2/5

  • Not safe to merge as-is: IPv6 IP identifiers are non-functional when ownership verification is enabled, and the IPv6 Host header violates RFC 7230.
  • Two P1 logic bugs were found: (1) isPrivateIp is IPv4-only and either throws or incorrectly evaluates IPv6 addresses, meaning IPv6 IP identifiers are broken in the default configuration; (2) the HTTP Host header during challenge validation lacks required brackets for IPv6 literal addresses. Together these could silently fail for the primary new use-case (IPv6 IPs) while also leaving IPv6 private/loopback addresses unguarded against SSRF if the throw path is ever changed.
  • backend/src/ee/services/pki-acme/pki-acme-service.ts (IPv6 private-IP guard) and backend/src/ee/services/pki-acme/pki-acme-challenge-service.ts (Host header brackets) need the most attention. The root cause is in backend/src/lib/ip/ipRange.ts, which needs IPv6 range support.

Important Files Changed

Filename Overview
backend/src/ee/services/pki-acme/pki-acme-service.ts Core ACME service updated to accept IP identifiers. Critical issue: isPrivateIp is IPv4-only and throws BadRequestError for any IPv6 address, making IPv6 support non-functional when skipDnsOwnershipVerification=false. Duplicate validation inside the transaction is also dead code.
backend/src/ee/services/pki-acme/pki-acme-challenge-service.ts IPv6 bracket handling added to URL construction is correct. However, the Host header still uses the raw identifier value without brackets for IPv6 addresses, violating RFC 7230 §5.4 and potentially breaking HTTP-01 validation for IPv6 hosts.
backend/src/ee/services/pki-acme/pki-acme-fns.ts Added validateIpIdentifier as a thin wrapper around isValidIp. Delegates correctly to Node.js net module for IP validation. No functional issues, though the wrapper adds minimal value.
backend/src/ee/services/pki-acme/pki-acme-schemas.ts Adds IP = "ip" to AcmeIdentifierType enum, consistent with RFC 8555/8738 terminology. Straightforward and correct change.

Comments Outside Diff (1)

  1. backend/src/ee/services/pki-acme/pki-acme-challenge-service.ts, line 99 (link)

    P1 IPv6 address in Host header missing required brackets

    Per RFC 7230 §5.4 and RFC 2732, a literal IPv6 address in an HTTP Host header must be enclosed in square brackets (e.g., [::1], [2001:db8::1]). Using a bare IPv6 string (e.g., ::1) here is non-compliant and may cause the HTTP-01 challenge response to be rejected by strictly-conforming ACME client servers.

    The URL construction on line 87–88 was correctly updated to bracket IPv6 hosts, but the Host header on this line still uses the raw identifierValue without brackets.

Last reviewed commit: "feat(pki): add IP ad..."

@saifsmailbox98 saifsmailbox98 force-pushed the saif/pki-145-pki-acme-error-ip-address-sans branch from 7361c8e to cf0a15c Compare March 20, 2026 17:53
@saifsmailbox98 saifsmailbox98 force-pushed the saif/pki-145-pki-acme-error-ip-address-sans branch from cf0a15c to 5b1e16a Compare March 20, 2026 17:54
@saifsmailbox98 saifsmailbox98 merged commit 5d5fcbb into main Mar 21, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PKI ACME error IP Address SANs

3 participants