Skip to content

fix: update eduroam CA certificates and improve connection handling - #110

Merged
Stensel8 merged 6 commits into
mainfrom
claude/github-issue-109-review-ckj0ve
Aug 31, 2026
Merged

fix: update eduroam CA certificates and improve connection handling#110
Stensel8 merged 6 commits into
mainfrom
claude/github-issue-109-review-ckj0ve

Conversation

@Stensel8

Copy link
Copy Markdown
Member

Summary

Updates the pinned RADIUS CA certificates from the outdated USERTrust/GEANT chain to the current HARICA roots that Saxion's server actually uses, and improves the connection activation flow with explicit timeouts and better error messaging.

Type of change

  • fix — bug fix (broken link, incorrect command, layout issue)
  • content — update or improve existing content

Details

Script Changes (saxion-eduroam.py)

Certificate Update:

  • Replaces pinned certificates with the actual chain served by ise.infra.saxion.net:
    • Hellenic Academic and Research Institutions RootCA 2015 (depth=3)
    • HARICA TLS RSA Root CA 2021 (depth=2)
  • Removes the outdated USERTrust RSA CA and GEANT OV RSA CA 4 that caused "unknown CA" failures after GÉANT's migration to HARICA
  • Adds comprehensive documentation explaining the certificate chain, why pinning is necessary, and how to refresh if Saxion changes CAs again

Connection Handling Improvements:

  • Adds CONNECT_TIMEOUT = 45 constant to prevent the script appearing frozen during the 90-second default nmcli wait
  • Passes --wait flag to nmcli with explicit timeout
  • Adds subprocess timeout as a backstop
  • Prints status message during connection attempt so users know the script is still running
  • Improves error handling to log full nmcli errors before checking for certificate failures
  • Adds graceful timeout handling with helpful guidance to check logs

File Permissions:

  • Changes CA certificate file permissions from 0600 to 0644, since these are public root certificates (not keys) and NetworkManager reads them as a system service

Documentation Changes

English (eduroam-network-installation.md):

  • Updates explanation of certificate pinning to reference HARICA roots instead of USERTrust/GEANT
  • Adds context about GÉANT's migration and the previous failure mode
  • Updates SHA256 checksum

Dutch (eduroam-network-installation.nl.md):

  • Parallel updates to Dutch documentation
  • Updates SHA256 checksum

Checklist

  • PR title follows the commit convention
  • Both EN and NL versions updated
  • No broken image references
  • Changes tested against actual certificate chain from live handshake

https://claude.ai/code/session_012kJxRh5QAtaz86aPkQLqpr

Claude added 3 commits August 31, 2026 13:56
…tlopen

Twee gebreken die het onderzoeken van #109 onmogelijk maakten.

run_nmcli() gaf bij 'Failed to recognize certificate' meteen False terug
zonder res.stderr te printen. Dat is precies het pad waarop de aanroeper
zegt 'See the terminal output above for what nmcli reported' - terwijl
dat de enige tak was die niks logde. De stderr wordt nu altijd eerst
gelogd, daarna pas op certificaatfouten getest.

'nmcli connection up' draaide met capture_output en zonder timeout.
nmcli wacht standaard 90 seconden, dus bij een falende EAP-handshake
zag de gebruiker anderhalve minuut lang helemaal niets - het symptoom
dat in #109 als 'stuck on loading' gemeld is. Er wordt nu vooraf een
regel geprint, --wait begrenst nmcli zelf, en een subprocess-timeout
vangt af als nmcli dat negeert. De timeout-tak verwijst naar de
journalctl-regel die de werkelijke oorzaak laat zien.

Refs #109
De hash in beide installatiepagina's hoort bij de vorige versie van het
script, dus sha256sum -c faalt nu en blokkeert de installatie. Deze
checksum wordt handmatig onderhouden - update-checksums.yml dekt alleen
de vastgezette CI-tools op Renovate-branches, niet dit bestand.

Refs #109
Sluit #109.

De gepinde keten klopte niet. Het script legde USERTrust RSA
Certification Authority en GEANT OV RSA CA 4 vast, maar GEANT heeft zijn
Trusted Certificate Service naar HARICA verhuisd en die twee komen in de
handshake helemaal niet meer voor. Een live PEAP-handshake tegen
ise.infra.saxion.net levert:

  depth=3  Hellenic Academic and Research Institutions RootCA 2015
  depth=2  HARICA TLS RSA Root CA 2021   (cross-signed door de 2015-root)
  depth=1  GEANT TLS RSA 1
  depth=0  ise.infra.saxion.net

wpa_supplicant liep daardoor vast op 'error 19 (self-signed certificate
in certificate chain) depth 3' gevolgd door 'SSL3 alert: fatal: unknown
CA'. NetworkManager bleef opnieuw proberen, dus de gebruiker zag een
verbinding die eindeloos bleef laden.

Vastgelegd worden nu de 2015-root, die byte-voor-byte gelijk is aan het
depth=3 certificaat dat de server stuurt, en de self-signed HARICA TLS
RSA Root CA 2021, zodat validatie blijft werken zodra GEANT de
cross-signature laat vallen. De GEANT TLS RSA 1 intermediate wordt
bewust niet vastgelegd: de server stuurt hem mee, en intermediates
roteren vaker dan roots.

Het CA-bestand krijgt 0644 in plaats van 0600. Het zijn publieke roots
en geen sleutel, en NetworkManager leest dit pad als systeemdienst bij
elke verbinding.

De SELinux-context van ~/.config bleek geen rol te spelen: er zijn geen
AVC denials en wpa_supplicant las het bestand zonder problemen. De
locatie blijft dus ongewijzigd en het script heeft nog steeds geen root
nodig.
Copilot AI lite review requested due to automatic review settings August 31, 2026 14:18

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@Stensel8 Stensel8 linked an issue Aug 31, 2026 that may be closed by this pull request
@Stensel8 Stensel8 self-assigned this Aug 31, 2026
Comment thread src/static/scripts/saxion-eduroam.py Fixed
CodeQL markeert de wijziging naar 0644 als py/overly-permissive-file
(high). Terecht: de mode was cosmetisch bedoeld, niet functioneel.

De reden om het te verruimen is er ook niet. Uit de logs bij #109 blijkt
dat wpa_supplicant het bestand op 0600 gewoon leest - de fout daar was
een certificaatverificatie, geen leesfout, en er stonden geen AVC
denials tegenover ondanks SELinux enforcing. NetworkManager leest dit
pad als root, en dat trekt zich van de mode niets aan.

Daarmee blijft de diff beperkt tot wat #109 daadwerkelijk oplost.
@Stensel8
Stensel8 requested a lite review from Copilot August 31, 2026 14:24

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@Stensel8

Copy link
Copy Markdown
Member Author

@Hintenhaus04, you can test if you want.

Claude added 2 commits August 31, 2026 14:30
51 naar 27 regels commentaar. De uitleg bij de gepinde keten was langer
dan de code eromheen en las als een essay. Wat blijft: welke roots, hoe
je ze naleest van een echte handshake, en waarom pinning de moeite waard
is. Wat weg is: de herhaling en het filosoferen.

Geen functionele wijziging - certificaten en gedrag zijn identiek.
Als de gepinde keten niet meer klopt, zoals in #109, valt er zonder
ontsnappingsluik weinig te onderzoeken. Deze vlag slaat CA-validatie
over en drukt af welke keten de server werkelijk stuurde, zodat de pin
te repareren is in plaats van alleen omzeild.

De vlag schreeuwt wat hij weggeeft, op de terminal en in de GUI: zonder
validatie wordt elk access point dat zich eduroam noemt vertrouwd, en
dat kan de MSCHAPv2-uitwisseling opvangen en offline kraken.
domain-suffix-match helpt daar niet tegen, want die controleert een naam
op een certificaat dat niemand geverifieerd heeft.

Gedocumenteerd in beide talen, met dezelfde waarschuwing. De callouts
gebruiken de bestaande **Bold:** conventie - deze site draait Hugo, dus
Starlight-achtige ::: blokken zouden als platte tekst renderen.
@Stensel8 Stensel8 added documentation Improvements or additions to documentation enhancement New feature or request labels Aug 31, 2026
@Stensel8
Stensel8 merged commit e043cb3 into main Aug 31, 2026
6 checks passed
@Stensel8
Stensel8 deleted the claude/github-issue-109-review-ckj0ve branch August 31, 2026 14:42
Stensel8 added a commit that referenced this pull request Aug 31, 2026
…connect race (#111)

Follow-up to #110. Pins the HARICA ECC roots alongside the RSA pair, documents where every trusted certificate comes from and why, removes the ~32 second stall on first connect.

## Type of change

- [x] `feat` — new page or feature
- [x] `fix` — bug fix (broken link, incorrect command, layout issue)
- [x] `content` — update or improve existing content

## Details

### Autoconnect race (`1629ad4`)

Measured on a real connection:

```
16:45:30.700  CTRL-EVENT-EAP-STARTED
              (nothing — no success, no failure)
16:46:02.340  SME: Trying to authenticate    31.6s later, retry
16:46:02.475  CTRL-EVENT-EAP-STARTED
16:46:02.577  CTRL-EVENT-EAP-SUCCESS         102ms
```

The handshake itself takes ~100 ms including four-deep chain validation. The 32 seconds before it is NetworkManager autoconnecting the moment the profile is added — before the user has typed anything — stalling in `EAP-STARTED` until it times out, and asking for the password a second time on the way. That was the double keyring prompt users saw.

The profile is now created with `connection.autoconnect no` so only the script activates it, then autoconnect is restored in a `finally` so a failed or timed-out activation does not leave a profile that never reconnects on its own.

### Self-diagnosis when the pin goes stale (`7d362a8`)

A stale pin looked like a hang: NetworkManager kept retrying and nothing on screen said the certificate was the problem. On activation failure the script now reads the journal for certificate errors and, if it finds them, prints the error, the chain the server actually served, and what to do about it. Without journal access it falls back to the command the user can run themselves.

Also adopted from the GÉANT CAT installer: `connection.permissions` so the profile belongs to whoever ran the script rather than every account on the machine, and `802-1x.auth-timeout` to bound a stalled EAP exchange.

Trust-on-first-use was considered and rejected: it would make the first connection rely on the system trust store (~150 CAs) where the official CAT method trusts two. Wider than what Saxion prescribes, so it stays out.

### HARICA ECC roots (`da9569a`)

Four pinned roots instead of two. The RSA pair is what the server serves today; the ECC pair covers a move off RSA. All four are HARICA roots, so this remains a single CA operator.

HARICA publishes the cross certificate as expiring **2029-08-31**. After that the chain must terminate at the self-signed 2021 root, which is already pinned — that transition is handled, and it is a date rather than a guess.

Dialogs now match the desktop: `kdialog` on KDE, `zenity` elsewhere. KDE installs frequently have zenity pulled in as somebody's dependency, which previously produced a GTK dialog on a Qt desktop.

Python requirement raised from 3.10 to 3.11 with a startup check so the stated minimum means something. This is a support decision, not a technical floor — the code runs on older versions.

### Provenance of the pinned certificates (`ac2d9ce`)

All four roots were verified against HARICA's own repository at repo.harica.gr. Every SHA-1 fingerprint matched the bytes in the script.

The comment block now states which source does which job: CAT supplies the connection parameters (verified to agree), the live handshake shows which roots are in use, and HARICA supplies the certificates. None is trusted on its own.

Both guides gained a section letting readers verify this themselves — HARICA's fingerprints next to a command that prints what is actually installed locally. The command was run; it returns exactly the four values in the table.

## Checklist

- [x] PR title follows the commit convention
- [x] Both EN and NL versions updated
- [x] No broken image references
- [x] `flake8` and `bandit -ll` clean; published SHA256 matches the script in both guides

Closes #109
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: Eduroam installer script fails to authenticate

3 participants