One VTU logoOne VTU
All posts
EngineeringAndroidTLS

VTU broke our result fetcher twice, and it was never VTU's fault

The VTU result server sends an incomplete certificate chain. Android then has to fetch the missing piece over plain HTTP — and blocks it. Here is how a misconfigured server becomes a bug in your app.

21 August 20264 min read

Fetching a VTU result from inside the app means opening results.vtu.ac.in in a WebView. For most of a year that worked. Then one morning it stopped, and the error on screen said the connection was not secure.

The cause turned out to be nothing we had changed, nothing VTU had broken, and something that will happen again.

A server that sends half a certificate

When a browser connects over HTTPS, the server is supposed to send a chain: its own certificate, plus the intermediate certificate that links it to a root authority your device already trusts.

VTU's result server sends only its own certificate. No intermediate.

openssl s_client -connect results.vtu.ac.in:443 -servername results.vtu.ac.in | grep -c "BEGIN CERTIFICATE"

That command returns 1. A correctly configured server returns more.

This is not fatal, because certificates carry a pointer — an Authority Information Access URL — telling clients where to fetch the missing intermediate. Desktop browsers quietly do that and the page loads. Android's WebView does the same thing.

There is just one detail. That fetch happens over plain HTTP. It has to. You cannot require a verified TLS connection in order to obtain the certificate you need in order to verify a TLS connection.

So we blocked it

The app ships a network security config that keeps cleartext HTTP off. That is the right default, and it is what lets us answer “encrypted in transit” honestly on the Play data safety form.

But it meant the AIA fetch was refused, the chain could not be completed, and the handshake failed:

E chromium: ssl_client_socket_impl.cc handshake failed;
  returned -1, SSL error code 1, net_error -202

-202 is ERR_CERT_AUTHORITY_INVALID.

What the student saw was a generic SSL error. Which is the worst kind of error message, because it looks like the VTU site is down. It is not. VTU was up the entire time.

The trap in the obvious fix

The obvious fix is to allow cleartext for vtu.ac.in.

It does nothing. The host being blocked is not VTU's. It is the certificate authority's — the domain in the AIA URL. When we first hit this the CA was Sectigo, and the blocked hosts were crt.sectigo.com and ocsp.sectigo.com.

So we allowed those, and it worked.

Then it broke again

In August, VTU renewed its certificate and the new one came from DigiCert. The AIA host was now cacerts.rapidssl.com.

Everything we had allowed was irrelevant, the fetch was blocked again, and the fix was a new app release. Which means any student who does not update stays permanently unable to fetch their results.

Two failures in a year, both from the same cause, neither predictable. The pattern was clear enough: allowlisting the incumbent CA is a fix that expires.

Allowlisting for the renewal, not the certificate

The config now lists the AIA and OCSP domains for twenty-five certificate authorities — the DigiCert group, the Sectigo group, Let's Encrypt, GoDaddy, GlobalSign, Entrust, Amazon Trust, Google Trust Services and the rest. Any of them could plausibly issue VTU's next certificate.

Two were deliberately left out:

  • microsoft.com and nic.in — allowing cleartext to these with includeSubdomains would open far more than a certificate endpoint, for no realistic benefit.

And the base configuration still refuses cleartext everywhere else. The exception is a short list of domains whose entire purpose is to hand out certificates.

What we would tell anyone hitting this

Do not guess. Read the live certificate and look at the Authority Information Access field — it names the host you actually need:

openssl s_client -connect host:443 -servername host \
  | openssl x509 -noout -text | grep -A2 "Authority Information Access"

And separate the two questions. “Is VTU up?” is a different question from “can my app verify VTU?”, and a generic SSL error answers neither.

The honest downside

This list is maintenance debt. It is a bet that the next CA VTU picks is one of twenty-five, and that bet is much better than a bet on one — but it is still a bet. The day VTU serves a complete chain, as a correctly configured server does, the entire block becomes dead weight and should be deleted.

We could instead bundle the intermediate certificate inside the app as a trust anchor. That removes the runtime fetch, and replaces one maintenance task with a worse one: hand-updating a pinned certificate every time the authority changes.

Sometimes the fix for someone else's misconfiguration is a list you have to keep updating.

Keep reading

Related reading

EngineeringAndroidProduct

The card you mark as known never comes back

Flashcards has three states and no spaced-repetition scheduler. Marking a card known removes it from revision permanently, and four different screens disagree about which cards are due.

16 September 20264 min read
EngineeringAndroidOffline

The Daily Quiz has no daily content, and that is deliberate

Daily Quiz seeds nothing by date and generates nothing when the app opens. The quizzes are the output of a durable background queue, and the only daily thing about the feature is which five of them we remind you about.

15 September 20264 min read
EngineeringAndroidOffline

We store no record of which dose you saw, on purpose

The Home card and the notification both need to know which item is today's. One of them runs in a background isolate that cannot open the database at all — so instead of syncing a cursor, we deleted it.

11 September 20266 min read