X.509: The Certificate and Its Fields
Chapter Sixty-Four
Syllabus topic Module 2, "Authentication Applications: X.509 Authentication"
Pages 402 to 412 of 678
In one line
An X.509 certificate is a small signed document that says "this public key belongs to this name", signed by an authority whose own public key you already trust.
In the words an answer should use: an X.509 certificate is a data structure, defined by ITU-T Recommendation X.509 and profiled for the Internet by RFC 5280, that binds a subject's name to a public key for a stated validity period; it is issued and digitally signed by a certification authority (CA), so that anyone holding the CA's public key can verify that the binding was made by that CA and has not been altered.
Why certificates exist
The key-distribution chapter of Module 1 ended on a problem: a public key is only useful if you know whose it is. Anyone can generate a key pair and announce "this is the bank's key". A certificate moves the question from "is this the bank's key?" to "did an authority I already trust say so?", and the second question can be answered by checking one signature.
The same chapter set out what a certificate scheme must allow: anyone can read a certificate and learn the owner's name and key; anyone can verify that it came from the CA and is not counterfeit; only the CA can create or change one; and anyone can check that it is still current. X.509 is the format that meets those four requirements, and it is the one the whole Internet uses.
Where X.509 comes from
X.509 is an ITU-T Recommendation, published jointly with ISO as ISO/IEC 9594-8. It was first published in 1988 as part of the X.500 series of Recommendations on directory services, and it defined the certificate format that the rest of the world then adopted. The Recommendation's own history table, and RFC 5280's account of it, give the dates:
| Year | What changed |
|---|---|
| 1988 | first edition; the certificate format of this edition is version 1 |
| 1993 | second edition; two optional fields added, the issuer and subject unique identifiers, giving version 2 |
| 1996 | the version 3 format completed (June 1996), adding extensions, and published in the 1997 edition |
| 2008 | RFC 5280 profiles version 3 for the Internet: which fields and extensions Internet software must support |
| 2019 | the current edition, approved in October 2019 and published as ISO/IEC 9594-8:2020 |
Version 3 is the only one worth learning in detail. RFC 5280 says that when extensions are used, "as expected in this profile, version MUST be 3". Every certificate a browser sees is version 3.
The certificate's three parts
At the top level a certificate has exactly three parts, and seeing them is most of understanding what a CA does:
tbsCertificate, "to be signed": every field that says something, the name, the key, the dates, the extensions.signatureAlgorithm: which algorithm the CA used to sign.signatureValue: the CA's signature on thetbsCertificatebytes, and on nothing else.
X.509: The Certificate and Its Fields
The signature covers the first part only. The CA hashes the encoded tbsCertificate and signs the hash with its private key. A verifier hashes the same bytes and checks the signature with the CA's public key. Change one byte of the first part and the check fails.
Every field, and what it is for
The fields of tbsCertificate, in order, as RFC 5280 s.4.1 defines them. The last column is the value in the certificate munotes.in served on 30 September 2026, read by the listing below.
| Field | What it holds | Why it is there | munotes.in's value |
|---|---|---|---|
| version | 1, 2 or 3, stored as 0, 1 or 2 | tells software which fields to expect | 3 |
| serialNumber | a positive integer, unique for this CA, at most 20 bytes | issuer name plus serial number identifies exactly one certificate; revocation lists name certificates by it | 18 bytes |
| signature | the algorithm the CA used | must equal the outer signatureAlgorithm | ecdsa-with-SHA384 |
| issuer | the CA's distinguished name | says whose public key verifies the signature | Let's Encrypt, YE1 |
| validity | notBefore and notAfter | the period in which the CA warrants it will keep status information about the certificate | 12 September to 11 December 2026 |
| subject | the owner's distinguished name | the name being bound to the key | CN=munotes.in |
| subjectPublicKeyInfo | the algorithm and the public key itself | the whole point of the certificate | an elliptic-curve key on P-256 |
| issuerUniqueID, subjectUniqueID | optional bit strings (version 2 and 3) | to tell apart two issuers or subjects with the same name | absent |
| extensions | a list of extra fields (version 3 only) | everything the first seven fields cannot say | ten of them |
A distinguished name is a name built from typed parts: country C, organisation O, common name CN, and others. C=US, O=Let's Encrypt, CN=YE1 is one.
Three details carry marks.
The validity period includes both ends. RFC 5280 says the period runs "from notBefore through notAfter, inclusive". munotes.in's certificate runs from 11:54:59 on 12 September to 11:54:58 on 11 December, which is 89 days, 23 hours, 59 minutes and 59 seconds apart, and so exactly 90 days counting both ends.
Dates are written in two forms. Up to 2049 a date is encoded as UTCTime, with a two-digit year; from 2050 it must be GeneralizedTime, with four. A certificate with no well-defined expiry date uses the notAfter value 99991231235959Z.
The issuer and serial number together name one certificate. That is why a revocation list, in the next chapter, is a list of serial numbers.
X.509: The Certificate and Its Fields
The textbook's notation
The prescribed textbook writes certificates in a compact notation, which is worth being able to read and to write.
Y<<X>>means the certificate of user X issued by CA Y.Y{I}means the information I, signed by Y: I together with Y's signature on it.- So a certificate of user A issued by a CA is written
CA<<A>> = CA {V, SN, AI, CA, UCA, A, UA, Ap, TA}where V is the version, SN the serial number, AI the signature algorithm identifier, CA the issuer's name, UCA the issuer's unique identifier, A the subject's name, UA the subject's unique identifier, Ap A's public key, and TA the validity period. The list is the tbsCertificate fields in order, and the braces say the CA signed them.
The 2019 Recommendation writes a signed item the same way, A{...} for information signed by A, and writes Ap for A's public key and Bp[...] for something encrypted under B's public key, which is the notation of the authentication procedures below.
Extensions
Version 3 added extensions, and every modern certificate depends on them. Each extension is three things: an object identifier naming it, a flag saying whether it is critical, and its value.
The critical flag is a rule about unknown extensions. RFC 5280 s.4.2: software "MUST reject the certificate if it encounters a critical extension it does not recognize"; a non-critical extension "MAY be ignored if it is not recognized, but MUST be processed if it is recognized". So a CA marks critical exactly the restrictions it cannot afford to have ignored.
X.509 itself sorts the standard extensions into groups, and the ones in munotes.in's certificate fall into all three:
Key and policy information.
- Key usage (critical in both certificates below): what the key may be used for. munotes.in's key may make digital signatures only; the CA's key may also sign certificates (
keyCertSign) and revocation lists (cRLSign). - Extended key usage: finer purposes by name.
serverAuthmeans a TLS server. - Subject key identifier and authority key identifier: short fingerprints of the subject's key and of the issuer's key. They let software find the issuer's certificate when a CA has more than one key: munotes.in's authority key identifier equals YE1's subject key identifier, and the run checks it.
- Certificate policies: which published rules the CA followed when it issued.
2.23.140.1.2.1is the CA/Browser Forum's "domain validated" policy: the CA checked only that the applicant controls the domain.
Subject and issuer information.
- Subject alternative name: the names the key really belongs to. For a website this is the list of host names, here
munotes.inandwww.munotes.in. This, not the subject's common name, is what a browser matches. RFC 9525, November 2023, is blunt: the Common Name "MUST NOT be used to identify a service", because it is free-form text.
X.509: The Certificate and Its Fields
Certification path constraints.
- Basic constraints (critical): whether the subject is a CA. munotes.in's says
CA: no, so its key must never be accepted as the signer of another certificate. YE1's saysCA: yes, path length 0: it may sign certificates, but no further CA may sit below it. RFC 5280 requires this extension, marked critical, in every CA certificate whose key signs certificates.
And three that tell software where to look:
- Authority information access: where to fetch the issuer's certificate,
http://ye1.i.lencr.org/. - CRL distribution points: where to fetch the revocation list that would name this certificate if it were revoked, the subject of the next chapter.
- Certificate Transparency timestamps: signed promises from public logs that this certificate will be added to them within a fixed time (RFC 6962), so that a certificate issued by mistake, or by a CA that has been attacked, cannot be issued in secret. munotes.in's carries two.
The run: reading munotes.in's certificate
The two files below are real certificates as munotes.in served them on 30 September 2026: its own, and its issuer's. A certificate on disk is usually PEM, base64 text between two marker lines; underneath is DER, the binary encoding of the ASN.1 structure RFC 5280 defines, where every item is a tag, a length and a value.
-----BEGIN CERTIFICATE-----
MIIDkjCCAxmgAwIBAgISBf++q0njvGQyUykj6Cj+EYiQMAoGCCqGSM49BAMDMDMx
CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQwwCgYDVQQDEwNZ
RTEwHhcNMjYwOTEyMTE1NDU5WhcNMjYxMjExMTE1NDU4WjAVMRMwEQYDVQQDEwpt
dW5vdGVzLmluMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEtlAU0VbQfEk4HTrX
5hIWuUpiQ20GHhNVuqE+ZDVD9ULSrOf4Kg8qSn0gtLQPRk5fVBf/1lUus8ioEKMA
V2+Tt6OCAikwggIlMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcD
ATAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBTYT4mXaBFZ9hSOXEPu3Mg0+5NmNTAf
BgNVHSMEGDAWgBS7IMpHC/7X5Zz5jwkqo4w3RbG82DAzBggrBgEFBQcBAQQnMCUw
IwYIKwYBBQUHMAKGF2h0dHA6Ly95ZTEuaS5sZW5jci5vcmcvMCUGA1UdEQQeMByC
Cm11bm90ZXMuaW6CDnd3dy5tdW5vdGVzLmluMBMGA1UdIAQMMAowCAYGZ4EMAQIB
MC4GA1UdHwQnMCUwI6AhoB+GHWh0dHA6Ly95ZTEuYy5sZW5jci5vcmcvMTcuY3Js
MIIBDQYKKwYBBAHWeQIEAgSB/gSB+wD5AHYA1219ENGn9XfCx+lf1wC/+YLJM1pl
4dCzAXMXwMjFaXcAAAGgla4X3QAABAMARzBFAiBCYhMg08b9CrBS19uyuz3wZStw
W7DE7t8ZSDPcUvBD4gIhAMD7yhJN64KP6bWG5H6ZA68VLvNZCiRLQrsvnH92e8bO
AH8AqCbL4wrGNRJGUz/gZfFPGdluGQgTxB3ZbXkAsxI8VScAAAGgla4azQAIAAAF
ADH5KHsEAwBIMEYCIQCQybl79cSWejo8WdCZ3O4BS7uIG/gVa+gwzM4PHheFCgIh
AIgzHibZCL4C2UUgOwU0rHkIHnhr05PVx6KajQca6AZiMAoGCCqGSM49BAMDA2cA
MGQCMAR9Skrz1wHkFWwr/d/D28Pjlo8+ZPALlN7CuZG728/ZJy+h/Wn68R5HhziI
YSN6OwIwRID/awRkE2KqxXBIPSQ+zj2S4d/UivmhZt2GHve0KRjTiuh1JUdx4iH1
MqrwigZp
-----END CERTIFICATE----------BEGIN CERTIFICATE-----
MIICizCCAhGgAwIBAgIQXd1w3TH4AchcGGp6BLgK/jAKBggqhkjOPQQDAzAuMQsw
CQYDVQQGEwJVUzENMAsGA1UEChMESVNSRzEQMA4GA1UEAxMHUm9vdCBZRTAeFw0y
NTA5MDMwMDAwMDBaFw0yODA5MDIyMzU5NTlaMDMxCzAJBgNVBAYTAlVTMRYwFAYD
VQQKEw1MZXQncyBFbmNyeXB0MQwwCgYDVQQDEwNZRTEwdjAQBgcqhkjOPQIBBgUr
gQQAIgNiAAQHZVB1/mimla2hfSurylScjPMZaOJXLz/NnAc2sylm8WDyhU9Ccp+z
ASQi5vSwGGJjSGklkD9fdPR8GpyDIOIjCEfrnbt/v+ZSEPLLEGbaM6EccDbN7p9x
teIm2Avf+ryjge4wgeswDgYDVR0PAQH/BAQDAgGGMBMGA1UdJQQMMAoGCCsGAQUF
BwMBMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFLsgykcL/tflnPmPCSqj
jDdFsbzYMB8GA1UdIwQYMBaAFKPIJlqOoUzQNWP8myPIOq5W809WMDIGCCsGAQUF
BwEBBCYwJDAiBggrBgEFBQcwAoYWaHR0cDovL3llLmkubGVuY3Iub3JnLzATBgNV
HSAEDDAKMAgGBmeBDAECATAnBgNVHR8EIDAeMBygGqAYhhZodHRwOi8veWUuYy5s
ZW5jci5vcmcvMAoGCCqGSM49BAMDA2gAMGUCMQDgjUEahFT/h3DRakqiPZpLvPgf
Zwkt6K2EOMmh1nvEzl83eMLYcod4GCl3b0J1Nn0CMBNYmEQJb4CEG5WoOe7aRn/L
VKu6saHmHEynI7ysIPd8zQsK1HdmhlHKlw9Z5GpGvA==
-----END CERTIFICATE-----The listing reads the DER with a forty-line reader, prints every field and extension, and then checks the CA's signature. The signature is ECDSA on the curve P-384, the elliptic-curve scheme of the signature standard chapters; the curve's constants are taken from FIPS 186-4 and checked before use.
# Every field of a real certificate, read from its bytes, and the CA's signature checked.
import base64, datetime, hashlib
def der_of(path): # PEM is base64 between two marker lines
lines = open(path).read().split('\n')
return base64.b64decode(''.join(l for l in lines if l and not l.startswith('-----')))
def tlv(d, i): # one DER element: (tag, value start, value end)
tag, n, j = d[i], d[i + 1], i + 2
if n & 0x80: # long form: the next (n - 128) bytes hold the length
k = n & 0x7F
n, j = int.from_bytes(d[j:j + k], 'big'), j + k
return tag, j, j + n
def items(d, start, end): # the elements inside a SEQUENCE, SET or wrapper
out, i = [], start
while i < end:
tag, s, e = tlv(d, i)
out.append((tag, s, e, i)) # i is where the whole element begins
i = e
return out
def oid(b):
arcs, v = [b[0] // 40, b[0] % 40], 0
for byte in b[1:]:
v = (v << 7) | (byte & 0x7F)
if not byte & 0x80:
arcs.append(v)
v = 0
return '.'.join(map(str, arcs))
NAMES = {'1.2.840.10045.4.3.3': 'ecdsa-with-SHA384', '1.2.840.10045.2.1': 'EC public key',
'1.2.840.10045.3.1.7': 'P-256', '1.3.132.0.34': 'P-384', '2.5.4.3': 'CN',
'2.5.4.6': 'C', '2.5.4.10': 'O', '2.5.29.15': 'keyUsage', '2.5.29.37': 'extKeyUsage',
'2.5.29.19': 'basicConstraints', '2.5.29.14': 'subjectKeyIdentifier',
'2.5.29.35': 'authorityKeyIdentifier', '1.3.6.1.5.5.7.1.1': 'authorityInfoAccess',
'2.5.29.17': 'subjectAltName', '2.5.29.32': 'certificatePolicies',
'2.5.29.31': 'cRLDistributionPoints', '1.3.6.1.4.1.11129.2.4.2': 'CT timestamps',
'1.3.6.1.5.5.7.3.1': 'serverAuth', '2.23.140.1.2.1': 'domain validated'}
USAGE = ['digitalSignature', 'nonRepudiation', 'keyEncipherment', 'dataEncipherment',
'keyAgreement', 'keyCertSign', 'cRLSign', 'encipherOnly', 'decipherOnly']
def name(d, s, e): # SEQUENCE of SET of (type, string)
parts = []
for _, s1, e1, _ in items(d, s, e):
for _, s2, e2, _ in items(d, s1, e1):
(_, a, b, _), (_, c, f, _) = items(d, s2, e2)
parts.append(NAMES.get(oid(d[a:b]), oid(d[a:b])) + '=' + d[c:f].decode())
return ', '.join(parts)
def when(d, s, e):
return datetime.datetime.strptime(d[s:e].decode(), '%y%m%d%H%M%SZ')
def uris(d, s, e, tag=0x86): # every [6] URI or [2] dNSName, however deep
found = []
for t, s1, e1, _ in items(d, s, e):
if t == tag:
found.append(d[s1:e1].decode())
elif t & 0x20: # constructed: look inside
found += uris(d, s1, e1, tag)
return found
def extension(d, key, s, e):
if key == 'keyUsage':
_, a, b = tlv(d, s)
bits = int.from_bytes(d[a + 1:b], 'big') << 8 >> 8
width = (b - a - 1) * 8
return ' '.join(u for k, u in enumerate(USAGE) if k < width and bits >> (width - 1 - k) & 1)
if key == 'basicConstraints':
inner = items(d, *tlv(d, s)[1:])
ca = bool(inner and inner[0][0] == 0x01 and d[inner[0][1]] != 0)
path = [int.from_bytes(d[a:b], 'big') for t, a, b, _ in inner if t == 0x02]
return 'CA: ' + ('yes' if ca else 'no') + (', path length %d' % path[0] if path else '')
if key == 'extKeyUsage' or key == 'certificatePolicies':
found, stack = [], [tlv(d, s)[1:]]
while stack:
a, b = stack.pop()
for t, s1, e1, _ in items(d, a, b):
if t == 0x06:
o = oid(d[s1:e1]); found.append(NAMES.get(o, o))
elif t == 0x30:
stack.append((s1, e1))
return ', '.join(found)
if key == 'subjectKeyIdentifier':
_, a, b = tlv(d, s)
return d[a:b].hex().upper()[:16] + '...'
if key == 'authorityKeyIdentifier':
_, a, b = tlv(d, s)
return d[items(d, a, b)[0][1]:items(d, a, b)[0][2]].hex().upper()[:16] + '...'
if key == 'subjectAltName':
return ', '.join(uris(d, *tlv(d, s)[1:], tag=0x82))
if key in ('authorityInfoAccess', 'cRLDistributionPoints'):
return ', '.join(uris(d, *tlv(d, s)[1:]))
if key == 'CT timestamps':
return '%d signed timestamps from public logs' % len(scts(d[s:e]))
return '(%d bytes)' % (e - s)
def scts(blob): # TLS-encoded list inside an OCTET STRING
_, a, b = tlv(blob, 0)
body, found, i = blob[a + 2:b], [], 0
while i < len(body):
n = int.from_bytes(body[i:i + 2], 'big')
found.append(body[i + 2:i + 2 + n]); i += 2 + n
return found
def read(path):
d = der_of(path)
_, s, e = tlv(d, 0)
(_, ts, te, tstart), (_, as_, ae, _), (_, ss, se, _) = items(d, s, e)
f = items(d, ts, te)
cert = {'der': d, 'tbs': (tstart, te), 'fields': f,
'version': d[items(d, f[0][1], f[0][2])[0][1]] + 1,
'serial': d[f[1][1]:f[1][2]],
'algorithm': NAMES[oid(d[items(d, f[2][1], f[2][2])[0][1]:items(d, f[2][1], f[2][2])[0][2]])],
'issuer': name(d, f[3][1], f[3][2]), 'subject': name(d, f[5][1], f[5][2]),
'from': when(d, *items(d, f[4][1], f[4][2])[0][1:3]),
'until': when(d, *items(d, f[4][1], f[4][2])[1][1:3])}
spki = items(d, f[6][1], f[6][2])
alg = items(d, spki[0][1], spki[0][2])
cert['curve'] = NAMES[oid(d[alg[1][1]:alg[1][2]])]
point = d[spki[1][1] + 1:spki[1][2]] # skip the unused-bits byte
half = (len(point) - 1) // 2
cert['Q'] = (int.from_bytes(point[1:1 + half], 'big'), int.from_bytes(point[1 + half:], 'big'))
cert['extensions'] = []
for _, xs, xe, _ in items(d, *tlv(d, f[7][1])[1:]):
parts = items(d, xs, xe)
key = NAMES.get(oid(d[parts[0][1]:parts[0][2]]), oid(d[parts[0][1]:parts[0][2]]))
critical = len(parts) == 3 and d[parts[1][1]] != 0
cert['extensions'].append((key, critical, extension(d, key, parts[-1][1], parts[-1][2])))
rs = items(d, ss + 1, se) # BIT STRING holding SEQUENCE {r, s}
cert['r'], cert['s'] = [int.from_bytes(d[a:b], 'big') for _, a, b, _ in items(d, rs[0][1], rs[0][2])]
return cert
leaf, ca = read('munotes-leaf.pem'), read('ye1.pem')
print('THE CERTIFICATE munotes.in SERVED ON 30 SEPTEMBER 2026 (%d bytes of DER)' % len(leaf['der']))
print(' version %d' % leaf['version'])
print(' serial number %s (%d bytes)' % (leaf['serial'].hex().upper(), len(leaf['serial'])))
print(' signature algorithm %s' % leaf['algorithm'])
print(' issuer %s' % leaf['issuer'])
print(' not before %s UTC' % leaf['from'])
print(' not after %s UTC' % leaf['until'])
print(' subject %s' % leaf['subject'])
print(' public key EC point on %s' % leaf['curve'])
print(' extensions, %d of them:' % len(leaf['extensions']))
for key, critical, value in leaf['extensions']:
print(' %-24s %-9s %s' % (key, 'critical' if critical else '', value))
span = leaf['until'] - leaf['from']
print(' validity %s, so %d days counting both ends' % (span, span.days + 1))
print()
print('ITS ISSUER, %s' % ca['subject'])
print(' issued by %s' % ca['issuer'])
print(' public key EC point on %s' % ca['curve'])
for key, critical, value in ca['extensions']:
if key in ('basicConstraints', 'keyUsage', 'subjectKeyIdentifier'):
print(' %-24s %-9s %s' % (key, 'critical' if critical else '', value))
ski = [v for k, c, v in ca['extensions'] if k == 'subjectKeyIdentifier'][0]
aki = [v for k, c, v in leaf['extensions'] if k == 'authorityKeyIdentifier'][0]
print(' the leaf\'s authority key identifier equals this subject key identifier:', aki == ski)
# ---- ECDSA verification on P-384 (constants from FIPS 186-4 D.1.2.4) ---------------------
p = 2**384 - 2**128 - 2**96 + 2**32 - 1
n = 0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973
b = 0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef
G = (0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7,
0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f)
a = p - 3
def add(P, Q):
if P is None: return Q
if Q is None: return P
if P[0] == Q[0] and (P[1] + Q[1]) % p == 0: return None
if P == Q: lam = (3 * P[0] * P[0] + a) * pow(2 * P[1], -1, p) % p
else: lam = (Q[1] - P[1]) * pow(Q[0] - P[0], -1, p) % p
x = (lam * lam - P[0] - Q[0]) % p
return (x, (lam * (P[0] - x) - P[1]) % p)
def mul(k, P):
R = None
while k:
if k & 1: R = add(R, P)
P, k = add(P, P), k >> 1
return R
def on_curve(P):
return (P[1] ** 2 - (P[0] ** 3 + a * P[0] + b)) % p == 0
def verify(tbs, r, s, Q):
e = int.from_bytes(hashlib.sha384(tbs).digest(), 'big')
w = pow(s, -1, n)
X = add(mul(e * w % n, G), mul(r * w % n, Q))
return X is not None and X[0] % n == r
print()
print('THE CA\'S SIGNATURE, CHECKED WITH NOTHING BUT INTEGERS')
print(' P-384 base point is on the curve, and n times it is the point at infinity:',
on_curve(G) and mul(n, G) is None)
print(' the issuer\'s public key is a point on P-384:', on_curve(ca['Q']))
tbs = leaf['der'][leaf['tbs'][0]:leaf['tbs'][1]]
print(' signed part of the leaf: %d bytes, hashed with SHA-384' % len(tbs))
print(' signature verifies with the issuer\'s key :', verify(tbs, leaf['r'], leaf['s'], ca['Q']))
forged = tbs.replace(b'munotes.in', b'munotes.io')
later = tbs.replace(b'261211115458Z', b'271211115458Z')
assert forged != tbs and later != tbs # prove each edit really changed the bytes
print(' one name changed, munotes.in to munotes.io:', verify(forged, leaf['r'], leaf['s'], ca['Q']))
print(' expiry moved a year later :', verify(later, leaf['r'], leaf['s'], ca['Q']))X.509: The Certificate and Its Fields
THE CERTIFICATE munotes.in SERVED ON 30 SEPTEMBER 2026 (918 bytes of DER)
version 3
serial number 05FFBEAB49E3BC6432532923E828FE118890 (18 bytes)
signature algorithm ecdsa-with-SHA384
issuer C=US, O=Let's Encrypt, CN=YE1
not before 2026-09-12 11:54:59 UTC
not after 2026-12-11 11:54:58 UTC
subject CN=munotes.in
public key EC point on P-256
extensions, 10 of them:
keyUsage critical digitalSignature
extKeyUsage serverAuth
basicConstraints critical CA: no
subjectKeyIdentifier D84F8997681159F6...
authorityKeyIdentifier BB20CA470BFED7E5...
authorityInfoAccess http://ye1.i.lencr.org/
subjectAltName munotes.in, www.munotes.in
certificatePolicies domain validated
cRLDistributionPoints http://ye1.c.lencr.org/17.crl
CT timestamps 2 signed timestamps from public logs
validity 89 days, 23:59:59, so 90 days counting both ends
ITS ISSUER, C=US, O=Let's Encrypt, CN=YE1
issued by C=US, O=ISRG, CN=Root YE
public key EC point on P-384
keyUsage critical digitalSignature keyCertSign cRLSign
basicConstraints critical CA: yes, path length 0
subjectKeyIdentifier BB20CA470BFED7E5...
the leaf's authority key identifier equals this subject key identifier: True
THE CA'S SIGNATURE, CHECKED WITH NOTHING BUT INTEGERS
P-384 base point is on the curve, and n times it is the point at infinity: True
the issuer's public key is a point on P-384: True
signed part of the leaf: 797 bytes, hashed with SHA-384
signature verifies with the issuer's key : True
one name changed, munotes.in to munotes.io: False
expiry moved a year later : FalseX.509: The Certificate and Its Fields
What the run establishes, in order.
X.509: The Certificate and Its Fields
Every field is there, in RFC 5280's order, and each matches what openssl x509 -text prints for the same file: version 3, an 18-byte serial number, the issuer YE1, 90 days of validity, the subject munotes.in, a P-256 key, and ten extensions.
X.509: The Certificate and Its Fields
The end-entity certificate and the CA certificate differ where the chapter says they do. munotes.in's key usage is digital signatures only and its basic constraints say CA: no; YE1's key usage adds certificate signing and revocation-list signing, and its basic constraints say CA: yes, path length 0.
The two certificates are linked by key identifiers. The leaf's authority key identifier equals YE1's subject key identifier.
The CA's signature verifies from nothing but integers. Hash the 797 signed bytes with SHA-384, run ECDSA verification on P-384 with YE1's public key, and the result is True.
Any change breaks it. One letter of the host name changed, munotes.in to munotes.io, and the signature fails. The expiry moved one year later, and it fails. This is the whole security of a certificate: its content can be read by anyone and changed by no one but the CA.
X.509's authentication procedures
Besides the certificate, X.509 describes how two parties who hold each other's certificates can authenticate. The current Recommendation keeps these in its Annex N, which describes five procedures; the three set in examinations are one-way, two-way and three-way. In each, a token is a small message signed by its sender.
The symbols: A{...} is information signed by A; tA is a timestamp holding an expiry; rA is a nonce, a number A never repeats; B is B's name; Bp[...] is information encrypted under B's public key.
One-way A -> B A{tA, rA, B}
Two-way A -> B A{tA, rA, B}
B -> A B{tB, rB, A, rA}
Three-way A -> B A{tA, rA, B}
B -> A B{tB, rB, A, rA}
A -> B A{rB, B}Any token may also carry signed data (sgnData) and a secret for B encrypted under B's public key (Bp[encData]), which is how a session key is sent.
| Procedure | What it proves | What the receiver checks | Needs synchronised clocks |
|---|---|---|---|
| One-way | the identity of A; that the token was made by A and meant for B; its integrity and freshness | A's certificate has not expired; the signature; that B is the named recipient; the timestamp is current; optionally that rA is not a replay | yes |
| Two-way | all of that, plus the same about B's reply to A | the same checks, made by A on B's token | yes |
| Three-way | the same as two-way | each side checks that its own nonce came back | no: the timestamps may be zero |
X.509: The Certificate and Its Fields
The three-way procedure is what removes the clocks. In the two-way procedure freshness rests on timestamps, so both clocks must agree, which is the Kerberos trade again. In the three-way procedure each party sends a nonce and demands it back signed by the other, so freshness rests on the nonces, and the Recommendation says the timestamps "need not be checked".
The 2019 edition adds two five-way procedures involving a third party it calls a trust broker, which checks both certificates for A and B. They are recorded here so that a reference to "five-way authentication" is recognised; the one-, two- and three-way procedures are the ones to know.
Distinctions that carry marks
| End-entity certificate | CA certificate | |
|---|---|---|
| Basic constraints | CA: no, or absent | CA: yes, critical, with an optional path length |
| Key usage | signatures, key agreement, key encipherment | adds keyCertSign and cRLSign |
| Example | munotes.in | Let's Encrypt YE1 |
| Critical extension | Non-critical extension | |
|---|---|---|
| Software that does not recognise it | must reject the certificate | may ignore the extension |
| Software that recognises it | must process it | must process it |
| Used for | restrictions that must not be skipped: basic constraints, key usage | information: key identifiers, where to fetch things |
| Version 1 (1988) | Version 2 (1993) | Version 3 (1996) | |
|---|---|---|---|
| Unique identifiers | no | yes | yes |
| Extensions | no | no | yes |
| In use today | rarely | no | everywhere |
What beginners get wrong here
Saying a certificate is encrypted. It is signed, not encrypted. Anyone can read every field of it, as the run does. The signature stops it being changed, not read.
Saying the CA signs the whole certificate. It signs the tbsCertificate part. The signature cannot sign itself.
Saying the common name identifies the website. Software matches the host name against the subject alternative name, and RFC 9525 forbids using the common name for that.
Thinking a certificate says the owner is honest. It says a CA checked a name against a key, under a stated policy. A domain-validated certificate proves only that the applicant controlled the domain when it applied.
Thinking a certificate within its dates is safe to trust. It may have been revoked. Checking that is the next chapter.
Quick revision
- X.509: ITU-T Recommendation, = ISO/IEC 9594-8; v1 1988, v2 1993 (unique identifiers), v3 June 1996 (extensions); Internet profile RFC 5280 (2008); current edition October 2019.
- Three parts:
tbsCertificate,signatureAlgorithm,signatureValue; the CA signs the hash of the first. - Fields: version, serial number, signature algorithm, issuer, validity (inclusive), subject, subject public key info, two unique identifiers, extensions.
- Notation:
CA<<A>> = CA {V, SN, AI, CA, UCA, A, UA, Ap, TA};Y{I}is I signed by Y. - Critical extension not recognised means reject; non-critical may be ignored.
- Key extensions: key usage, extended key usage, subject and authority key identifiers, certificate policies, subject alternative name (what browsers match), basic constraints (CA or not, path length), authority information access, CRL distribution points.
- Authentication procedures: one-way
A{tA, rA, B}; two-way addsB{tB, rB, A, rA}; three-way addsA{rB, B}and needs no synchronised clocks.
X.509: The Certificate and Its Fields
Test yourself
1. Define an X.509 certificate and name its three top-level parts. It is a data structure, standardised by ITU-T X.509 and profiled for the Internet by RFC 5280, in which a certification authority binds a subject's name to a public key for a validity period and signs the result. Its three parts are the tbsCertificate, holding every field to be signed; the signatureAlgorithm, naming the algorithm the CA used; and the signatureValue, the CA's signature on the encoded tbsCertificate.
2. List the fields of a version 3 certificate and state what each is for. Version, which tells software which fields to expect; serial number, unique for the issuing CA; signature, the algorithm the CA used; issuer, the CA's name; validity, the not-before and not-after dates; subject, the owner's name; subject public key information, the algorithm and the key; the optional issuer and subject unique identifiers; and extensions, which carry everything else, such as key usage, basic constraints and the subject's alternative names.
3. Write the textbook's notation for a certificate of user A issued by a CA, and explain each symbol. CA<<A>> = CA {V, SN, AI, CA, UCA, A, UA, Ap, TA}. V is the version, SN the serial number, AI the signature algorithm identifier, CA the issuer's name, UCA the issuer's unique identifier, A the subject's name, UA the subject's unique identifier, Ap A's public key and TA the validity period; the braces preceded by CA mean the whole list is signed by the CA.
4. What does it mean for an extension to be marked critical? It means that software that does not recognise the extension, or cannot process what it contains, must reject the whole certificate. A non-critical extension may be ignored by software that does not recognise it. CAs mark critical the restrictions that must not be skipped, such as basic constraints and key usage.
X.509: The Certificate and Its Fields
5. How do the basic constraints of munotes.in's certificate and of its issuer differ, and why? munotes.in's certificate says CA: no, so its key may never be accepted as the signer of another certificate; it belongs to a website, not an authority. Its issuer YE1 says CA: yes with a path length of zero, so it may sign certificates, but only end-entity ones: no further CA may appear below it in a chain.
6. Explain the three-way authentication procedure, and what it gains over the two-way one. A sends B a token signed by A containing a timestamp, a nonce rA and B's name; B replies with a token signed by B containing its own timestamp, a nonce rB, A's name and rA; A then sends a token signed by A containing rB and B's name. Each party checks that its own nonce came back signed by the other. Because freshness rests on the returned nonces, the timestamps need not be checked, so the parties do not need synchronised clocks, which the two-way procedure does.
7. A browser connects to www.munotes.in. Which field does it match the host name against? The subject alternative name extension, which lists munotes.in and www.munotes.in. The subject's common name is not used: RFC 9525 says the Common Name must not be used to identify a service.
The rest of this subject
These notes are cut from the University's printed syllabus. Open the syllabus itself for the same subject.