Lesson 10 / 16
Certificate Life Cycle
Revocation as a round debt: how many exchanges not asking costs, the round asking adds per exchange, the knowledge delay of the options in between, and the symptoms of misconfiguration seen at the client.
Contents
The previous lesson closed the transport envelope and counted what the intermediary lost. Underneath the closed envelope stood one assumption: the client had verified the server’s chain and built the setup on it. That verification was valid at the moment it was made.
A certificate has a start and an end; between the two it can be revoked. Revocation cannot be written into the document, because the document freezes the moment it is signed — anything written afterward breaks the signature. This lesson’s question follows from that: how is something unwritable in the document known, and what does knowing it cost? Chain verification ran without asking; revocation cannot be known without asking. The difference between the two is a round debt.
The Certificate’s Life and Where Revocation Sits
Life is the span between the two timestamps in the certificate’s validity field, sitting inside the document, under the signature. That is why the validity check is local: the client looks at its own clock and asks no one.
Renewal is issuing a new document before life runs out. It does not extend the old document — extending it would mean changing a signed field. A new document is produced, the old document stays valid until its own end, and the two live side by side for a while. If the key has changed, the old document says nothing about the new key.
Revocation is declaring the binding invalid before its life runs out. Its causes sit outside the document: the private key falling into other hands, the name changing ownership, the binding having been set up wrong from the start. None of these can be written into the document afterward, so the issuer publishes a separate record.
life cycle
request -> signing -> distribution -> use -> renewal -> ... -> expiration
|
+-- revocation: at any moment, from outside the document
fields that carry life
serial number : names the document uniquely within the issuer
validity : start .. end <- life is this span
issuer : intermediate-1.test <- the party that will publish the revocation
revocation record
list issuer : intermediate-1.test
issue moment : the moment this list was produced
next issue : the moment the list will be refreshed <- upper bound on knowledge delay
entries : serial number | revocation moment | reason
This listing is not executed; it shows what the fields declare. The record names the document by serial number without changing it — it drops a note outside it. The asymmetry sits here: validity is read from inside the document, revocation from outside it. The first needs no round trip, the second does.
The Setup of the Measurement
The setup matches the rest of the course: the North Slope measurement station presents a measurement to a client, and on every exchange the client decides whether the presented certificate is still valid.
- GT1. The measurement window is 960 hours and forty exchanges happen inside it; exchange moments are drawn from the generator within the window.
- GT2. The revocation moment is tried separately at every hour of the window: 960 moments are swept, and forty exchanges are evaluated for each moment.
- GT3. The oracle — the truth behind the decision — is known because we produced the scenario: the certificate is invalid on every exchange after the revocation moment.
- GT4. The time until the client learns of the revocation is the knowledge delay; every exchange that falls within that span is a false acceptance.
- GT5. The revocation list’s refresh interval is 24 hours, the presented response’s freshness is 6, the short-lived certificate’s life is 12, and the long-lived one’s is 2160; all four are model values chosen within the lesson, with no version claim.
- GT6. The chain is three rungs — the leaf and two intermediate certificates; the trust anchor is not asked.
- GT7. The round is only the round trip the client pays; a round trip paid by the server or the record’s publisher does not enter this column.
- GT8. No connection is opened, no certificate is resolved; the listings are the scenario.
At a single revocation moment the set is forty decisions, resolution 1/40 = 0.025; the average columns are drawn from all 960 moments — 38,400 decisions total.
The Cost of Not Asking and Asking
SEED = 20260809 WINDOW = 960 # hours: forty-day measurement window LIFE = 2160 # hours: the long-lived certificate's modeled life RUNGS = 3 # leaf plus two intermediate certificates; the anchor is not asked def generator(seed: int): d = seed % 2147483646 + 1 def r(n: int) -> int: nonlocal d d = (d * 48271) % 2147483647 return d % n return r generate = generator(SEED) TIMES = sorted(generate(959) for _ in range(40)) REGIMES = ( # name, round per exchange, refresh interval (hours), client fetches it itself ("not asking", 0, None, False), ("asking every exchange", 1, 0, True), ("pre-distributed revocation list", 0, 24, True), ("response presented with certificate", 0, 6, False), ("short-lived certificate", 0, 12, False), ) def knowledge_moment(revoked_at: int, interval) -> int: if interval is None: return LIFE if interval == 0: return revoked_at return revoked_at + interval - revoked_at % interval def measure(interval) -> tuple[float, int, float, int]: delay_total = false_total = delay_worst = false_worst = 0 for revoked_at in range(WINDOW): known_at = knowledge_moment(revoked_at, interval) false_count = sum(1 for t in TIMES if revoked_at <= t < known_at) delay_total, false_total = delay_total + known_at - revoked_at, false_total + false_count delay_worst = max(delay_worst, known_at - revoked_at) false_worst = max(false_worst, false_count) return delay_total / WINDOW, delay_worst, false_total / WINDOW, false_worst def client_rounds(per_exchange: int, interval, fetches: bool, count: int, rungs: int) -> int: rounds = per_exchange * count * rungs return rounds + (WINDOW // interval * rungs if fetches and interval else 0) print(f"{'regime':<38s}{'round/exchange':>16s}{'client rounds':>15s}" f"{'knowledge delay':>18s}{'false acceptance':>19s}") for name, per_exchange, interval, fetches in REGIMES: dg, dw, fg, fw = measure(interval) print(f"{name:<38s}{per_exchange:16d}" f"{client_rounds(per_exchange, interval, fetches, len(TIMES), RUNGS):15d}" f"{f'{dg:.1f} / {dw}':>18s}{f'{fg:.2f} / {fw}':>19s}") print() print(f"{'rungs':>7s}{'ask every exchange':>21s}{'revocation list':>18s}" f"{'presented response':>21s}") for h in range(1, 6): row = [client_rounds(b, a, c, len(TIMES), h) for _, b, a, c in REGIMES[1:4]] print(f"{h:7d}{row[0]:21d}{row[1]:18d}{row[2]:21d}") print() print(f"{'exchanges':>10s}{'ask every exchange':>21s}{'revocation list':>18s}") for n in (40, 120, 400, 4000): row = [client_rounds(b, a, c, n, RUNGS) for _, b, a, c in REGIMES[1:3]] print(f"{n:10d}{row[0]:21d}{row[1]:18d}") print() print(f"exchanges {len(TIMES)}, revocation moments {WINDOW}, " f"decisions {len(TIMES) * WINDOW}")
regime round/exchange client rounds knowledge delay false acceptance
not asking 0 0 1680.5 / 2160 22.02 / 40
asking every exchange 1 120 0.0 / 0 0.00 / 0
pre-distributed revocation list 0 120 12.5 / 24 0.57 / 4
response presented with certificate 0 0 3.5 / 6 0.15 / 2
short-lived certificate 0 0 6.5 / 12 0.31 / 3
rungs ask every exchange revocation list presented response
1 40 40 0
2 80 80 0
3 120 120 0
4 160 160 0
5 200 200 0
exchanges ask every exchange revocation list
40 120 120
120 360 120
400 1200 120
4000 12000 120
exchanges 40, revocation moments 960, decisions 38400
The first table’s first two rows are the lesson’s two extremes. A client that never asks spends zero rounds and treats a revoked certificate as valid for an average of 22.02 exchanges; in the worst case, for all forty. The reason is not subtle: not asking leaves only the document’s own end as a source of information, and that end sits far past the window.
A client that asks on every exchange brings false acceptance down to zero. The 120 rounds it pays come from two factors: forty exchanges times three rungs. The round per exchange looks like 1, but as many questions as there are rungs are asked, because each rung of the chain can be revoked separately.
The second table unpacks that factor and sharpens the distinction at the course’s axis. In the Certificates and the Trust Chain lesson, chain verification’s round was independent of chain length; the revocation question’s round is directly proportional to it: 40 at one rung, 200 at five. The document’s inside arrives with the chain; the outside does not, and is asked for separately for every rung.
The third table shows the divide. Asking’s round grows linearly with the exchange count — 120 at forty exchanges, 12,000 at four thousand — but the pre-distributed list’s round stays fixed: 120. The list is paid once per window, the question once per exchange. That the two come out equal on the forty-exchange row is a coincidence; the distinction is not in the total but in where the round is written.
The Options in Between
The table’s last three rows fill the space between the two extremes, sharing one property: the round per exchange is zero. None of them adds a round trip to the exchange’s path; where they diverge is the knowledge delay.
The pre-distributed revocation list refreshes once a day; the delay averages 12.5 hours, 24 in the worst case, and an average of 0.57 exchanges is falsely accepted. The response presented with the certificate is a validity response from the issuer sent along with the certificate during setup; the client’s round is zero, because the response is already inside a message that was going to arrive anyway. The delay drops to 3.5 hours, false acceptance to 0.15. The short-lived certificate, in turn, discards the revocation mechanism entirely: the document lives so briefly it never needs revoking, and the delay is the remaining life — an average of 6.5 hours, false acceptance 0.31.
Reading the three rows side by side, a pattern emerges. At a delay of 3.5, false acceptance is 0.15; at 6.5, it is 0.31; at 12.5, it is 0.57. False acceptance grows with the delay, roughly in proportion to it. So even though the mechanisms carry different names, what is measured is a single number: choosing a mechanism is choosing a delay.
The revocation question itself is a surface that has to be counted too: it tells the answering party which document is being looked at, and asking on every exchange also reveals the exchange frequency. Narrowing: when the response is presented together with the certificate, the client never asks, so there is no notification either; the pre-distributed list carries the whole list rather than individual documents, so it reveals nothing about which document is being looked at. Not asking’s surface sits in the table’s first row — an average of 22.02 exchanges. Narrowing: the only thing that narrows that window is the document’s life.
As Life Shortens
SEED = 20260809 WINDOW = 960 # hours: forty-day measurement window LIFETIMES = (2160, 720, 168, 72, 24, 12, 6) # hours def generator(seed: int): d = seed % 2147483646 + 1 def r(n: int) -> int: nonlocal d d = (d * 48271) % 2147483647 return d % n return r generate = generator(SEED) TIMES = sorted(generate(959) for _ in range(40)) def measure(life: int) -> tuple[float, float, int]: delay_total = false_total = false_worst = 0 for revoked_at in range(WINDOW): known_at = revoked_at + life - revoked_at % life false_count = sum(1 for t in TIMES if revoked_at <= t < known_at) delay_total, false_total = delay_total + known_at - revoked_at, false_total + false_count false_worst = max(false_worst, false_count) return delay_total / WINDOW, false_total / WINDOW, false_worst print(f"{'life (hours)':>13s}{'renewals':>10s}{'avg delay':>13s}" f"{'false acceptance':>19s}{'renewals x life':>17s}") for life in LIFETIMES: dg, fg, fw = measure(life) renewals = WINDOW // life print(f"{life:13d}{renewals:10d}{dg:13.1f}{f'{fg:.2f} / {fw}':>19s}" f"{renewals * life:17d}")
life (hours) renewals avg delay false acceptance renewals x life
2160 0 1680.5 22.02 / 40 0
720 1 420.5 13.02 / 28 720
168 5 87.5 3.82 / 8 840
72 13 37.1 1.32 / 4 936
24 40 12.5 0.57 / 4 960
12 80 6.5 0.31 / 3 960
6 160 3.5 0.15 / 2 960
This table has no revocation mechanism; the client learns that something has become invalid only when the document ends. The two columns move in opposite directions. At a life of 2160 hours, no renewal happens within the window, the delay averages 1680.5 hours, and 22.02 exchanges are falsely accepted. When life drops to 6 hours, the delay falls to 3.5 hours and false acceptance to 0.15 — but 160 renewals have to happen within the window.
The last column shows the total work is conserved: on every row where life is shorter than the window, renewal count times life equals the window. The delay gained is inversely proportional to the renewal count paid. 160 renewals in forty days means one roughly every six hours; that is not work done by hand. A short life is a condition for automation, and if the condition is not met, the gain turns into a cost.
One more observation is not a coincidence. This table’s 24-, 12-, and 6-hour rows give the same numbers as the previous table’s revocation-list, short-lived-certificate, and presented-response rows. Three separate mechanisms are a function of a single parameter. The mechanism’s name does not change the false acceptance count; the only thing it changes is who pays the round, when, and how many times.
Symptoms of Misconfiguration
Verification is not a single decision but a walk, and each step of the walk can fail separately. The symptom gives away which step failed.
verification walk and the steps it can fail at 1 the presented chain was collected <- a missing intermediate certificate fails here 2 every rung's signature was verified 3 did the chain reach the trust anchor <- a self-signed chain fails here 4 is the validity interval open <- an expired certificate fails here 5 does the leaf's name satisfy the requested name <- a name mismatch fails here 6 has one of the rungs been revoked <- only this step asks outside the document
- Expired certificate. Symptom: verification fails at the fourth step and the failure begins at a single moment, because the interval is the same for everyone. The distinguishing mark: the failure does not vary with network, path, or client. Narrowing: if renewal is triggered before the end, the interval never closes; as life shortens, this trigger has to become automated.
- Missing intermediate certificate. Symptom: the same server works on some clients and not on others. A client that acquired and cached the missing rung elsewhere can complete the chain; one that did not cannot. The distinguishing mark is that the outcome varies by client. Narrowing: the missing rung is closed by adding it to the chain the server presents, not by widening the client’s anchor set.
- Name mismatch. Symptom: the signatures hold, the chain reaches the anchor, the validity interval is open, and verification still fails at the fifth step. The distinguishing mark: the failure depends on which name was used. Narrowing: if the name set the certificate declares and the name set the server answers to come from a single source, the two cannot diverge.
- Self-signed chain. Symptom: the chain is a single rung and that rung’s issuer is itself; without a match in the client’s anchor set, it fails at the third step. The distinguishing mark is that the failure is not seen on a client that has placed the anchor by hand. This does not mean a self-signed document is flawed — trust anchors themselves are mostly self-signed too; the distinction is whether the document is in the client’s hand. Narrowing: if an anchor is placed, its scope is narrowed to a single endpoint, because every anchor makes every chain descending from it acceptable.
All four are the failure of one step of verification. Turning verification off entirely silences all four symptoms at once, and because it silences them, it is not a fix — the Certificates and the Trust Chain lesson measured that a client that never verifies has a lower count of correct decisions. This lesson writes down what is wrong, not how to do it.
Summary
- Life sits inside the document and is checked locally; revocation sits outside the document and, because it cannot be written into a signed field, is published as a separate record.
- Renewal does not extend the old document, it issues a new one; the two live side by side for a while, and if the key has changed, the old document says nothing about the new key.
- A client that never asks spends zero rounds and treats a revoked certificate as valid for an average of 22.02 exchanges; a client that asks on every exchange zeroes out false acceptance and pays 120 rounds.
- The revocation question’s round is directly proportional to chain length — 40 at one rung, 200 at five — and grows linearly with exchange count, while the pre-distributed list’s round stays fixed.
- The three options in between have zero round per exchange, and their false acceptance depends only on the knowledge delay: 0.15 at 3.5 hours, 0.31 at 6.5, 0.57 at 12.5.
- As life shortens, the delay drops but renewals rise; renewal count times life is fixed to the window, so the delay gained is inversely proportional to the renewals paid.
Next Step
Secure Transport closes here. Key roles were split, the chain was verified locally, setup’s round was counted, and revocation’s round debt was paid. The loss measured in the TLS Handshake lesson still stands too: once the envelope closed, 160 decisions had moved from the intermediary to the endpoints. But in the middle of that loss, the connection was still shaped as request–response: the client sends a message, the server returns one, and the turn passes back to the client. Even though the intermediary could not see inside the message, it knew how many messages there were and where each one started and ended. The next topic asks: if the connection’s shape changes too, what remains?
To keep your progress and take notes, Log in
My notes
Log in to take notes.