Skip to content

Initial cert validation test#2582

Open
benjaminleonard wants to merge 20 commits into
mainfrom
tls-cert-soft-validation
Open

Initial cert validation test#2582
benjaminleonard wants to merge 20 commits into
mainfrom
tls-cert-soft-validation

Conversation

@benjaminleonard
Copy link
Copy Markdown
Contributor

Fixes #2580 and related to #2578

Idea from @augustuswm to soft validate the cert. Unfortunately I think we need a library to parse the cert but I lazy imported it to avoid adding to the main bundle since most users will not see this.

Principally the risk here is what I dont know about certs:

  1. wildcard handling might need to be sophisticated
  2. certs that arrange slightly different in a way that parseCertificate() doesn't catch

But feels, like the image soft validation, that it could be a good quality of life improvement for something that is potentially very painful when not done correctly. We might want to label the CN and SAN on the messages list of found names.

image

@vercel
Copy link
Copy Markdown

vercel Bot commented Nov 27, 2024

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
console Ready Ready Preview May 21, 2026 11:21am

Request Review

Comment thread app/components/form/fields/TlsCertsField.tsx Outdated
Comment thread package.json Outdated
@benjaminleonard
Copy link
Copy Markdown
Contributor Author

Added tests, improved wildcard handling and also a message in case the certificate cannot be parsed.

image

Message copy needs work.

@benjaminleonard
Copy link
Copy Markdown
Contributor Author

Do we have a good way of getting the domain? I vaguely remember some discussion around with the IdP setup.

@charliepark
Copy link
Copy Markdown
Contributor

@augustuswm
Copy link
Copy Markdown

This looks awesome, thanks for picking it up. I think initial rack install will certainly benefit from it.

@benjaminleonard
Copy link
Copy Markdown
Contributor Author

Is this your card? https://github.com/oxidecomputer/console/blob/require_tls_cert/app/forms/idp/util.ts#L16-L17

Do we need some copy to caveat incase that is not correct. I remember some talk about a proxy perhaps throwing it off?

const { data: certValidation } = useQuery({
queryKey: ['validateImage', ...(file ? [file.name, file.size, file.lastModified] : [])],
queryFn: file ? () => file.text().then(parseCertificate) : skipToken,
})
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@charliepark pointed out we might want to set the stale time directly here. I'm going to experiment with that and also maybe tweaking the query key.

@david-crespo
Copy link
Copy Markdown
Collaborator

david-crespo commented Apr 27, 2026

Tweaked the copy and fixed a bug where it would only do validation if the silo name was non-empty in the parent form. I changed it so it only opts out of the part of the validation that requires the silo name.

image

The hardcoded r2.oxide-preview.com produces a false "domain mismatch"
warning on every rack that isn't r2 (dogfood, colo, customer installs).
Reuse the same helper the IdP create form uses to derive the suffix
from window.location.
- Rename stale 'validateImage' query key to 'validateCert'
- Drop redundant *.sys.<domain> match arm: it's subsumed by
  expectedDomain matching (a *.sys.<domain> SAN already matches
  <silo>.sys.<domain>) and only the early return guards the
  empty-siloName case anyway
- Rename commonName to commonNames (it's a string[])
- Spread certValidation ?? {} so the undefined-spread isn't subtle
- Tighten "Could not be parsed" copy
getField('CN') and .map() both already return string[]. Replace the
hand-wavy bare-'*' comment with the RFC 6125 reference.
- Normalize case and strip trailing dots on both pattern and domain up
  front (RFC 6125 §6.4 case-insensitive, RFC 4592 trailing-dot FQDN).
  Wildcard branch was previously case-sensitive.
- Reject pathological '*.' which would have matched any 2-label domain
  via endsWith('') being true.
Users frequently paste a chain (leaf + intermediates). The previous
single-PEM parse would throw and report "Couldn't parse" for a valid
file. Extract the first PEM block (the leaf, by convention) and parse
that. Side benefit: tolerates leading whitespace / BOM.
parseCertificate now returns notAfter; CertDomainNotice renders a
'notice'-variant message when the cert is past its expiry. Expiry and
domain-mismatch warnings can stack — they're independent. Factored the
duplicated docs-link block into a SiloCertsDocsLink helper.
- Assert "Couldn't parse certificate" appears after the existing garbage
  chooseFile upload
- Swap the second cert upload to a real (expired, non-matching) PEM and
  assert both the expiry and mismatch notices render, plus that the
  parse-failure notice is gone
Before the bad-PEM step, upload a self-signed cert whose SANs cover
other-silo.sys.placeholder and isn't expired. Confirms the
soft-validation notices are absent in the happy path, not just present
in the unhappy one.
@benjaminleonard
Copy link
Copy Markdown
Contributor Author

Updated from main and a little review:

Major

  • Replaced r2.oxide-preview.com with getDelegatedDomain(window.location) as per @charliepark's snippet

Smaller polish

  • Renamed the stale validateImage query key, dropped the redundant match arm
  • matchesDomain now normalizes case (wildcard branch was case-sensitive) and trailing dots up front, and rejects the pathological *. pattern.
  • Warns when the uploaded cert is already past its notAfter. Stacks with the domain-mismatch warning when both apply.

Tests

  • Vitest: wildcard + uppercase, trailing dot, *. rejection, multi-PEM bundle, whitespace/BOM, expiry parse.
  • Playwright (silos.e2e.ts): asserts "Couldn't parse certificate" on the existing garbage upload, then uploads a valid matching cert (no notice fires) and a real expired non-matching PEM (both notices fire), exercising the FileField → useQuery → parseCertificate → matchesDomain → notice pipeline end to end.

Can we get one last sanity check and revisit merging?

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.

TLS cert soft failure

4 participants