In the context of public key cryptography, certificates are a way to prove the identity of the owner of a public key. While public key cryptography allows us to communicate securely through an insecure network, it leaves the problem of identity untouched. Once we established an encrypted communication we can be sure that the data we send and receive cannot be read or tampered with by third parties. But how can we be sure that the entity on the other side of the communication channel, with which we initiated the communication, is what it claims to be? In other words, the messages cannot be read or modified by malicious third-parties, but what if we established communication with a malicious actor in the first place? Such a situation can arise during a man-in-the-middle attack, where the low-level network communication is hijacked by a malicious actor who pretends to be the desired recipient of the communication. In the context of the Internet, and in particular of the World Wide Web, the main concern is that the server that provides services we log into (think of every service that has your personal or financial data like you bank, Google, Facebook, Netflix, etc.) is run by the company that we trust and not by an attacker who wants to steal our data. In this post I will try to clarify the main components of the certificates system and to explain the meaning of the major acronyms and names that you might hear when you deal with this part of web development. Clarification: SSL vs TLS In the world of web development and infrastructure management, we normally speak of SSL protocol and of SSL certificates, but it has to be noted that SSL (Secure Sockets Layer) is the name of a deprecated protocol. The current implementation of the protocol used to secure web applications is (Transport Layer Security). TLS The story of SSL and TLS is rich of events and spans 25 years since its inception by Taher Elgamal at Netscape. In short, SSL had 3 major versions (the first of which was never publicly used), and was replaced by TLS in 1999. TLS itself has gone through 3 revisions at the time of writing, TLS 1.3 being the latest version available. The TLS/SSL nomenclature is one of many sources of confusion in the complicated world of security and applied cryptography. In this article I will use only the acronym TLS, but I went for SSL in the title because I wanted the subject matter to be recognisable also by developers that are not much into security and cryptography. X.509 certificates While the problem of the identity in an insecure network can be solved in several ways, the solution embraced to secure the World Wide Web is based on a standard called . When we mention SSL certificates, we usually mean X.509 certificates used in a TLS connection, such as that created by HTTPS. X.509 X.509 is the ITU-T standard used to represent certificates, and has been chosen to be the standard used in the TLS protocol. The standard doesn't only define the binary structure of the certificate itself, but it also defines procedures to revoke the certificates, and establishes a hierarchical system of certification known as , or . certificate path certificate chain The structure of an X.509 certificate is expressed using , a notation used natively by the PEM format (discussed ). You can read the full specification in , in particular "Certificate and Certificate Extensions Profile". I will refer to this later when I will have a look at a real certificate. ASN.1 here RFC 2459 Section 4 How are certificates related to HTTPS? Before I discuss how certificates solve the problem of identity (or ownership of a public key), let's clarify the relationship between them and HTTPS. HTTPS stands for HTTP Secure, and the core of the protocol consists of running HTTP over TLS. When we access a web site with HTTPS the browser first establishes a TLS connection with the server and then communicates with it using pure HTTP. This means that the whole HTTP protocol is encrypted, as the secure channel is established outside it, and also means that, aside from the different URI scheme instead of , there are no differences between the two protocols. https:// http:// Certificates come into play when the browser establishes the TLS connection, which is why you need to set-up HTTPS as part of your infrastructure and not in your web application. By the time the HTTP requests reach your application they are already decrypted and accessible in plain text, as the HTTP protocol mandates. We usually say that we "terminate TLS" when a component of our infrastructure manages certificates and decrypts HTTPS into HTTP. How do certificates work? The X.509 standard establishes entities called (CAs), and creates a hierarchy of trust called between them. The idea is that there is a set of entities that are trusted worldwide by operating systems, browsers, and other network-related software, and that these entities can trust other entities, thus creating a trust network. Certificate Authorities chain While the market of Certificate Authorities is dominated by three major commercial players (see the )there are approximately 100 organisations operating worldwide, among which some non-profit ones. Not all of these are trusted by all operating systems or browsers, though. usage statistics The set of CAs trusted by an organisation is called . The Mozilla community runs a program that is independent from the hardware/software platform, aptly called and uses data contained in the (CCADB). Private companies such as Microsoft, Apple, and Oracle run their own root programs and software running on the respective platforms (Windows, macOS/iOS, Java) can decide to trust the CAs provided by those programs. root program Mozilla's CA Certificate Program Common CA Database In the open-source world, the Mozilla root program is by far the most influential and important source of information, being used by other software packages and Linux distributions. It is possible to create certificates that are not signed by any CA, and these are called . Such certificates can be used with any software that relies on certificates, but it requires such a software to disable certificate checking with the Certificate Authorities. Self-signed certificates are obviously useful for testing purposes, but there are scenarios in which it might be desirable not to rely on the CAs and establish a private network of trust. self-signed certificates Example: CA root certificate The certificates for root CAs that are part of the Mozilla root program can be retrieved from the web page, or can be seen in the Firefox directly. On a running Firefox browser you can open the [Privacy & Security](about:preferences#privacy) menu and click on "View Certificates" at the bottom of the page. The CAs are listed under the tab "Authorities". Common CA Database source code The interesting thing you can do here is to export a CA certificate. If you do it Firefox will save it in a file with extension , that contains data in PEM format. I exported the certificate for and I ended up with the file . If, instead of exporting, you view the certificate, you will end up in a page that allows you to download the certificate and the chain, both in PEM format, in files with the extension . As you see, you are not the only one who is confused. .crt Amazon Root CA 1 AmazonRootCA1.crt .pem I described the PEM format [in a post on RSA keys]({filename}rsa-keys.markdown) so I won't repeat here the whole discussion about it. The ("Textual Encodings of PKIX, PKCS, and CMS Structures") describes certificates in section 5. Section 4 mentions the module for , , and ("Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile"). RFC 7468 id-pkix1-e Certificate CertificateList SubjectPublicKeyInfo RFC 5280 The identifier is part of a registry of objects to be used in ASN.1 data created in the framework of the Public-Key Infrastructure using X.509 (PKIX) Working Group, that defined the infrastructure around the X.509 certificates system. Basically it's a standard way to identify binary objects and their structure. You can see a full list of all the objects in ("Object Identifier Registry for the PKIX Working Group"). Not a very exciting one to read, if you ask me. id-pkix1-e RFC 7299 I can dump the content of the Amazon Root CA 1 certificate with OpenSSL $ openssl asn1parse -inform pem - amazon-root-ca pem :d= hl= l= cons: SEQUENCE :d= hl= l= cons: SEQUENCE :d= hl= l= cons: cont [ ] :d= hl= l= prim: INTEGER : :d= hl= l= prim: INTEGER : C9FCF99BF8C0A39E2F0788A43E696365BCA :d= hl= l= cons: SEQUENCE :d= hl= l= prim: OBJECT :sha256WithRSAEncryption :d= hl= l= prim: NULL :d= hl= l= cons: SEQUENCE :d= hl= l= cons: SET :d= hl= l= cons: SEQUENCE :d= hl= l= prim: OBJECT :countryName :d= hl= l= prim: PRINTABLESTRING :US :d= hl= l= cons: SET :d= hl= l= cons: SEQUENCE :d= hl= l= prim: OBJECT :organizationName :d= hl= l= prim: PRINTABLESTRING :Amazon :d= hl= l= cons: SET :d= hl= l= cons: SEQUENCE :d= hl= l= prim: OBJECT :commonName :d= hl= l= prim: PRINTABLESTRING :Amazon Root CA :d= hl= l= cons: SEQUENCE :d= hl= l= prim: UTCTIME : Z :d= hl= l= prim: UTCTIME : Z :d= hl= l= cons: SEQUENCE :d= hl= l= cons: SET :d= hl= l= cons: SEQUENCE :d= hl= l= prim: OBJECT :countryName :d= hl= l= prim: PRINTABLESTRING :US :d= hl= l= cons: SET :d= hl= l= cons: SEQUENCE :d= hl= l= prim: OBJECT :organizationName :d= hl= l= prim: PRINTABLESTRING :Amazon :d= hl= l= cons: SET :d= hl= l= cons: SEQUENCE :d= hl= l= prim: OBJECT :commonName :d= hl= l= prim: PRINTABLESTRING :Amazon Root CA :d= hl= l= cons: SEQUENCE :d= hl= l= cons: SEQUENCE :d= hl= l= prim: OBJECT :rsaEncryption :d= hl= l= prim: NULL :d= hl= l= prim: BIT STRING :d= hl= l= cons: cont [ ] :d= hl= l= cons: SEQUENCE :d= hl= l= cons: SEQUENCE :d= hl= l= prim: OBJECT :X509v3 Basic Constraints :d= hl= l= prim: BOOLEAN : :d= hl= l= prim: OCTET STRING [HEX DUMP]: FF :d= hl= l= cons: SEQUENCE :d= hl= l= prim: OBJECT :X509v3 Key Usage :d= hl= l= prim: BOOLEAN : :d= hl= l= prim: OCTET STRING [HEX DUMP]: :d= hl= l= cons: SEQUENCE :d= hl= l= prim: OBJECT :X509v3 Subject Key Identifier :d= hl= l= prim: OCTET STRING [HEX DUMP]: CC8534ECBC0C94942E08599CC7B2104E0A08 :d= hl= l= cons: SEQUENCE :d= hl= l= prim: OBJECT :sha256WithRSAEncryption :d= hl= l= prim: NULL :d= hl= l= prim: BIT STRING in -1. 0 0 4 833 4 1 4 553 8 2 2 3 0 10 3 2 1 02 13 2 2 19 066 34 2 2 13 36 3 2 9 47 3 2 0 49 2 2 57 51 3 2 11 53 4 2 9 55 5 2 3 60 5 2 2 64 3 2 15 66 4 2 13 68 5 2 3 73 5 2 6 81 3 2 25 83 4 2 23 85 5 2 3 90 5 2 16 1 108 2 2 30 110 3 2 13 150526000000 125 3 2 13 380117000000 140 2 2 57 142 3 2 11 144 4 2 9 146 5 2 3 151 5 2 2 155 3 2 15 157 4 2 13 159 5 2 3 164 5 2 6 172 3 2 25 174 4 2 23 176 5 2 3 181 5 2 16 1 199 2 4 290 203 3 2 13 205 4 2 9 216 4 2 0 218 3 4 271 493 2 2 66 3 495 3 2 64 497 4 2 15 499 5 2 3 504 5 2 1 255 507 5 2 5 30030101 514 4 2 14 516 5 2 3 521 5 2 1 255 524 5 2 4 03020186 530 4 2 29 532 5 2 3 537 5 2 22 04148418 561 1 2 13 563 2 2 9 574 2 2 0 576 1 4 257 Let's read part of it using the aforementioned . section 4 of RFC 5280 The signed certificate is a sequence of three main components : Certificate := SEQUENCE { tbsCertificate TBSCertificate, signatureAlgorithm AlgorithmIdentifier, signatureValue BIT STRING } and the structure represents the unsigned certificate (TBS = To Be Signed) TBSCertificate TBSCertificate ::= { version [ ] EXPLICIT Version v1, serialNumber CertificateSerialNumber, signature AlgorithmIdentifier, issuer , validity Validity, subject , subjectPublicKeyInfo SubjectPublicKeyInfo, issuerUniqueID [ ] UniqueIdentifier , -- , version MUST be v2 or v3 subjectUniqueID [ ] UniqueIdentifier , -- , version MUST be v2 or v3 extensions [ ] EXPLICIT Extensions -- , version MUST be v3 } SEQUENCE 0 DEFAULT Name Name 1 IMPLICIT OPTIONAL If present 2 IMPLICIT OPTIONAL If present 3 OPTIONAL If present Comparing this with the output of OpenSSL we can find fields such as version :d= hl= l= prim: INTEGER : 10 3 2 1 02 which according to the documentation is 3 (binary ). Many values are of type , so they are readable already in the ASN.1 dump. 02 PRINTABLESTRING The validity of the certificate is :d= hl= l= prim: UTCTIME : Z :d= hl= l= prim: UTCTIME : Z 110 3 2 13 150526000000 125 3 2 13 380117000000 and following section 4.1.2.5.1 of the RFC we find out that the certificate is valid between 26 May 2015 and 17 Jan 2038. You can easily read these values in the certificate page in the browser without getting an headache trying to decode ASN.1. The CA signed the certificate using a certain algorithm. The algorithm identifier is repeated twice, first in the structure ( ) and then in the structure ( ). The two fields must have the same value. Certificate signatureAlgorithm AlgorithmIdentifier TBSCertificate signature AlgorithmIdentifier 34: =2 =2 l= 13 cons: SEQUENCE 36: =3 =2 l= 9 prim: OBJECT :sha256WithRSAEncryption 47: =3 =2 l= 0 prim: [ .] 561: =1 =2 l= 13 cons: SEQUENCE 563: =2 =2 l= 9 prim: OBJECT :sha256WithRSAEncryption 574: =2 =2 l= 0 prim: d hl d hl d hl NULL .. d hl d hl d hl NULL For this certificate, the algorithm used by Amazon is . This label is described in ("Additional Algorithms and Identifiers for RSA Cryptography for use in the Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile") as "PKCS #1 version 1.5 signature algorithm with SHA-256". The specific algorithm can be found in [RFC 2313](https://tools.ietf.org/html/rfc2313) ("PKCS #1: RSA Encryption Version 1.5"). As the name of the algorithm suggests, the certificate is first digested with SHA-256 and then encrypted using RSA and the private key of the signer. sha256WithRSAEncryption RFC 4055 Speaking of keys, the public key the CA used for the certificate can be found in the field , which is again made of a field type and a bit string with the value of the key. In this case the fields are subjectpublickeyinfo AlgorithmIdentifier 205: =4 =2 l= 9 prim: OBJECT :rsaEncryption 216: =4 =2 l= 0 prim: 218: =3 =4 l= 271 prim: BIT STRING d hl d hl NULL d hl The algorithm is described in ("Algorithms and Identifiers for the Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile"), section 2.3.1 as rsaEncryption RFC 3279 RSAPublicKey ::= { modulus , publicExponent } SEQUENCE INTEGER -- n INTEGER -- e ( ) or in ("PKCS #1: RSA Cryptography Specifications Version 2.2") sic RFC 8017 RSAPublicKey ::= { modulus , publicExponent } SEQUENCE INTEGER -- n INTEGER -- e We can then use the option of the module to find the actual values -strparse asn1parse $ openssl asn1parse -inform pem - amazon-root-ca pem -strparse :d= hl= l= cons: SEQUENCE :d= hl= l= prim: INTEGER :B2788071CA78D5E371AF478050747D6ED8D78876F4 F7582160F97484012FAC022D86D3A0437A4EB2A4D036BA01BE8DDB48C80717364CF4EE8823C73EEB37F5B5 F84968B0DED7B976381D619EA4FE8236A5E54A56E445E1F9FDB416FA74DA9C9B35392FFAB02050066C7AD080 B2A6F9AFEC47198F503807DCA2873958F8BAD5A9F948673096EE94785E6F89A351C0308666A14566BA54EBA3C3 F948DCFFD1E8302D7D2D747035D78824F79EC4596EBB738717F2324628B843FAB71DAACAB4F29F240E2D4BF7 C5E69FFEA9502CB388AAE50386FDBFB2D621BC5C71E54E177E067C80F9C8723D63F40207F2080C4804C3E3B AE6C9AC8AA0D :d= hl= l= prim: INTEGER : in -1. 218 0 0 4 266 4 1 4 257 9968 19 91 715 24268E04 265 1 2 3 010001 As we already saw for [RSA keys]({filename}rsa-keys.markdown)), OpenSSL has a specific module for important structures, and the X.509 certificates are definitely worth a module aptly called . using that we can easily decode any certificate x509 $ openssl x509 -inform pem - amazon-root-ca pem -noout -text Certificate: Data: Version: ( ) Serial Number: : c: :cf: :bf: c: a: :e2:f0: : a: :e6: : : b:ca Signature Algorithm: sha256WithRSAEncryption Issuer: C = US, O = Amazon, CN = Amazon Root CA Validity Not Before: May : : GMT Not After : Jan : : GMT Subject: C = US, O = Amazon, CN = Amazon Root CA Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public-Key: ( bit) Modulus: :b2: : : :ca: :d5:e3: :af: : : : : d: e:d8:d7: : :f4: : :f7: : : :f9: : : : :ac: : d: :d3:a0: : a: e:b2:a4:d0: :ba: :be: d:db: :c8: : : : c:f4:ee: : :c7: e:eb: :f5:b5: :f8: : :b0:de:d7:b9: : : d: : e:a4:fe: : :a5:e5: a: :e4: : e1:f9:fd:b4: :fa: :da: c: b: : : :fa:b0: : : : c: a:d0: :b2:a6:f9:af:ec: : : : : : :dc:a2: : : :f8:ba:d5:a9:f9: : : : :ee: : : e: : :a3: :c0: : : :a1: : :ba: :eb:a3:c3: :f9: :dc:ff:d1:e8: : d: d: d: : : :d7: : :f7: e:c4: : e:bb: : : :f2: : : :b8: :fa:b7: d:aa:ca:b4: f2: : : e: d: b:f7: : c: e: :ff:ea: : : cb: : a:ae: : : :db:fb: d: : b:c5:c7: e: :e1: :e0: :c8: : c: : :d6: : : : : : :c4: : c: e: b: : : e: :ae: c: a:c8: aa: d Exponent: ( ) X509v3 extensions: X509v3 Basic Constraints: critical CA:TRUE X509v3 Key Usage: critical Digital Signature, Certificate Sign, CRL Sign X509v3 Subject Key Identifier: : :CC: : :EC:BC: C: : : E: : : C:C7:B2: : E: A: Signature Algorithm: sha256WithRSAEncryption :f2: : a: : :a1: a:c5: : : : : : : e:ae:e6: :bb:aa:f8: :ae: :a4: : : b:fc: : d: b:b4:c8:a1: :f6:b6:f1: a: :c8: : :cc: : :e3: : :cf: :a4: f9:de: :d3: c: : :ad: e: a: : a:c2: b: a: : : : : : : : c: d: : e: b: : a:cb:f4:b5:a7: :d7: : c: :e8: : b:ad:e9: :a0: : e:f5:f2:f0:c5:b2:ed: b: b7:dc:fa: : c: : e: :a5: : :ad: :f2:f8: : b:de: b: c: b:ca: a: : b: :af: :f7: b:ef:a3:fb: : : : d: : :fc: :d3:c7: : : :ad:d9: : : : a:d9: : : :d1: : : : : e: : :c2: : c: : : :cf: : : : e: : :a5:d4:e4:cb: :fb: : : :e8: : : : :a1:a9: d: e: :d4: :ae:b8:d8:ce: :c2:d0: :f2: : f6:c4: : : : : :c0:b9:e8: :d7: : : : : e: a: :ae:a5:d1: d:ba: : e: : c: b: a:b9: : :f8:eb:c4: :be:f1:b9 in -1. 3 0x2 06 6 9f 99 8 0 39 78 8 43 96 36 5 1 26 00 00 00 2015 17 00 00 00 2038 1 2048 00 78 80 71 78 71 47 80 50 74 7 6 88 76 99 68 58 21 60 74 84 01 2f 02 2 86 43 7 4 36 01 8 48 07 17 36 4 88 23 3 37 19 49 68 76 38 1 61 9 82 36 4 56 45 16 74 9 9 35 39 2f 20 50 06 6 7 80 47 19 8f 50 38 07 87 39 58 48 67 30 96 94 78 5 6f 89 51 30 86 66 45 66 54 91 48 30 2 7 2 74 70 35 88 24 9 59 6 73 87 17 32 46 28 43 1 9f 24 0 2 4 71 5 5 69 95 02 38 8 50 38 6f 2 62 1 1 54 77 67 0f 9 87 23 3f 40 20 7f 20 80 80 4 3 3 24 26 8 04 6 9 0 65537 0x10001 84 18 85 34 0 94 94 2 08 59 9 10 4 0 08 98 37 5 41 90 1 76 51 28 20 36 23 0 28 94 48 30 7f 1 24 8 4 97 7 70 53 93 08 28 98 25 23 21 7 85 09 4 9 75 3 0 6 89 78 76 44 47 18 65 6 8 41 8 3 7f 9 50 05 2 37 03 4 61 02 6 5 94 5 77 9 13 7f 52 95 93 3 8 5 5 5 52 5 60 14 4 9f 40 95 6 31 54 42 46 1f 23 0f 48 70 9 75 78 71 72 43 34 75 6 57 59 02 5 26 60 29 23 19 16 8 88 43 08 23 11 43 43 29 72 62 5 5 08 90 14 55 86 93 43 77 66 61 41 97 78 60 03 6 4 72 7 10 9 86 6 1 8 59 33 90 Now I'm pretty sure you want to kill me because I could have shown you this from the start. But I like to understand things, and the easy path doesn't always make everything clear. At any rate, here you have a way to read an X.509 certificate in PEM format. Please note that in this certificate the and the are the same entity, as this is a root certificate, which is signed by the same entity that creates it. Issuer Subject Issuer: = US, = Amazon, CN = Amazon CA [...] Subject: = US, = Amazon, CN = Amazon CA C O Root 1 C O Root 1 Moreover, one of the version 3 extensions of the self-signed certificate is a basic constraint with the boolean set to true. It also has the extension set to , which means that the certificate can be used to sign other certificates. CA Key Usage Digital Signature, Certificate Sign, CRL Sign Example: self-signed certificate You can use OpenSSL to create a self-signed certificate using the module that you would normally use to create certificate requests. As a self-signed certificate doesn't need approval, the module can directly output the certificate. req $ openssl req rsa: Generating a RSA key .+++++ .+++++ writing key ----- -x509 -newkey 2048 -keyout self -signed -key.pem -out self -signed.pem -days 365 -nodes -subj '/CN=localhost' private ... ... ... ... ... ... new private to 'self-signed-key.pem' (note that for simplicity's sake I specified the option that prevents the key to be protected with a password, but this is a bad practice). This command creates the two files I mentioned, (the private key) and . -nodes self-signed-key.pem self-signed.pem We can read the certificate using the module x509 $ openssl x509 -inform pem - self-signed.pem -noout -text Certificate: Data: Version: ( ) Serial Number: :e5: : e: : : :b8:ac: :cb: d: c: : : :a9:fe: :ec Signature Algorithm: sha256WithRSAEncryption Issuer: CN = localhost Validity Not Before: Nov : : GMT Not After : Nov : : GMT Subject: CN = localhost Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public-Key: ( bit) Modulus: :b7: :ef: b:eb: b:a9: : :c5:d2:eb: d: : d:e4:a3: :f3:df:ce:b7:d3: : : :eb: : : a2: : a:cd: : :ae:e0:a5:ac:a7: :cf:a1: : a: :ca:e7: : a:a5:c0: : :ef:bb: : d: : :db:a7:bd:fa: b: : a:be:e9: b:bb: : : : dc: : : c:bc: d: b: : : :e9: b: a: a: d: cc: : :ba: b: :df: :ff: b: :ef: a:b7:c5: : :ce: : c: : : : : : a: b: : :b6: b3: e:aa:c3: :c3: : : : : : :e4: : : c: : :d2: : :d9: :ab: : : : :cc:c2: :be: : : :ea: : : : : d: :eb:a1: : :ce:d2: :f9:ee: :db: : :e8: :d0: : : : e: : d: : :d1: d: : : : a: : e: a: : :aa: a: a: b: :a7: : :ef: b: : a: : b:b6:c9:a7: e: : : : : : : : : : e: aa: :af: b:ee:f5: : b: :da: : c:b2: : : :a4:ee: e: :e6: : b:ba:cf:d3: d:d7:a3:ea: c4:bf Exponent: ( ) X509v3 extensions: X509v3 Subject Key Identifier: : B:C1:FC: : : :B7: :D1: F:E7: D: : : A: : : : C X509v3 Authority Key Identifier: keyid: : B:C1:FC: : : :B7: :D1: F:E7: D: : : A: : : : C X509v3 Basic Constraints: critical CA:TRUE Signature Algorithm: sha256WithRSAEncryption : b: b:c8: :b8: : :af: : a:d9: :ce:e3: d: a:c7: : :b0: : : a: :b3:b4: c:e5: : c:bf: :ad: e: c: : : e:b7:ef: d: : :bb: :d9: e: a:d3: : : a:ff: f2: :b1: : : : e: : : a: : :c9:d5:f5: a: : : a: : c: e: : : :e5: a: :d8:f8:e1:f2:c1:f1: :d0: d2: e: : :fe: a:ca: :b6: :e9:b5:a4: : : : : : :da: c:e3:fe: :f2:bd:f2: : :f4: :e3: d: c: a:e5: a: :cd: :b0: b:af: : e: d: e: b:a5:df: a: a: : : b3:b2: : c: : : : :a2:c1: : : : : :fa: a: d: :e5: : : c: e: :a8:b5:ab:f7: : :e3: : e:d4: d: :fc: : : d: : : : d: : d: :b0:e9: : c:e4: b: :c2: :c4:d5: b:de: :da:df:d8:a0: :a4: a:f2: e:ca: e: :a6: : : : : : b:db:eb: b: c:a8:f8: : : c: e:b1: : :cc:fe: :b0:cb: c: : b: a: : :dc: e:f5: :ba: :db in 3 0x2 46 2f 8 42 82 43 88 6 0 2f 71 28 00 3 00 23 34 2020 3 00 23 34 2021 2048 00 14 3 8 40 18 1 4f 5 17 3f 52 58 61 02 68 0 0f 97 88 15 0 97 03 8 66 38 59 4 48 17 4 50 2 5 59 65 71 99 73 9 4 3 42 97 91 3 1 8 9 41 38 8 8f 65 5 1f 8 93 07 15 4 13 72 78 59 64 9 5 95 20 8 29 7f 28 39 43 81 59 0f 26 7 3f 49 06 05 54 09 65 96 01 72 85 1f 40 94 35 04 09 9 87 90 36 55 08 52 78 70 25 89 13 8 0f 9 98 98 4 67 06 8f 8 61 9 3 73 89 0 0 1 05 52 32 1 78 5 5f 4 4 15 10 04 50 99 00 09 2f 60 8 20 6 60 0 29 38 1 73 14 99 5 89 77 0 5 65537 0x10001 64 7 99 74 56 82 4 2 94 77 1 09 52 26 5 64 7 99 74 56 82 4 2 94 77 1 09 52 26 5 43 7 0 98 6f 72 39 4 76 9 3 9f 14 4f 20 0 45 8 37 4 15 8 5 45 4f 3 8 60 57 6f 5 6 04 05 4 66 76 66 59 7 24 89 0 50 28 7 00 07 8 79 9 6 53 43 66 9 10 17 9 50 80 2 08 98 82 23 31 45 35 33 2 54 61 91 32 7 4 3 3 0f 36 8 9f 8 3 0 0 4 3 91 83 5f 3 47 81 73 4f 49 06 75 17 25 5 8 30 55 7f 9 3 15 45 38 76 8 0 60 42 17 3 85 72 41 1 53 9 58 29 0 6 14 22 7 36 4f 0 3 7 66 10 38 97 24 73 5 0 6 37 15 2 0 82 44 85 6 26 4 4 70 33 7 84 07 As you can see this certificate has the same value in and , as happened before for the Amazon Root one. It also has the flag set to true but it doesn't have the extension meaning that this certificate can't be used to sign other certificates. Issuer Subject CA Key Usage Example: The Digital Cat's certificate [This article was first published on my blog, so I used that as a practical example. The content of this section can be applied to any website.] You can see TLS certificates and the chain of trust in action on . Following the documentation of you browser (instructions for Firefox are ), you can see the certificate used by The Digital Cat. At the time of writing the blog is hosted on GitHub Pages, even tough I'm using a custom domain, and GitHub partnered with to provide certificates for such a configuration (details ). my blog here Let's Encrypt here Indeed, the certificate for is provided by "Let's Encrypt Authority X3", which in turn is trusted by Digital Signature Trust Co. with its root CA "DST Root CA X3". thedigitalcatonline.com Let's have a look at the three certificates. The one for The Digital Cat is ( ) Serial : : : : : : d9 Signature sha256WithRSAEncryption C = US, O = Let s Encrypt Authority X3 Validity Not Oct : : GMT Not Jan : : GMT CN = www.thedigitalcatonline.com [...] X509v3 X509v3 Key critical Digital Signature, Key Encipherment X509v3 Extended Key TLS Web Server Authentication, TLS Web Client Authentication X509v3 Basic critical FALSE X509v3 Subject Key : : : : : : : : : : : X509v3 Authority Key : : : : : A1 Authority Information OCSP - CA Issuers - X509v3 Subject Alternative www.thedigitalcatonline.com [...] Certificate: Data: Version: 3 0x2 Number: 03: 93 02 bb: 9 a: c9: ed: a5: c3: d1: 16 00 8 b: 15 76 af: e5: Algorithm: Issuer: 's Encrypt, CN = Let' Before: 22 04 53 28 2020 After : 20 04 53 28 2021 Subject: extensions: Usage: Usage: Constraints: CA: Identifier: 63: 4 E: 15 85 56 5 A: A4: 94 02 C2: 16 42 A4: A5: 97 9 A: 38 02 57 97 Identifier: keyid: A8: 4 A: 6 A: 63 04 7 D: DD: BA: E6: D1: 39 B7: A6: 45 65 EF: F3: A8: EC: Access: URI: http: //ocsp.int-x3.letsencrypt.org URI: http: //cert.int-x3.letsencrypt.org/ Name: DNS: And you can see that this time the is , but the is . The certificate provided by the organisation is Subject www.thedigitalcatonline.com Issuer Let's Encrypt Authority X3 Let's Encrypt Certificate: Data: Version: ( ) Serial Number: a: : : : : : : : : : a: b: :ec:a7: Signature Algorithm: sha256WithRSAEncryption Issuer: O = Digital Signature Trust Co., CN = DST Root CA X3 Validity Not Before: Mar : : GMT Not After : Mar : : GMT Subject: C = US, O = Let s Encrypt Authority X3 [...] X509v3 extensions: X509v3 Basic Constraints: critical CA:TRUE, pathlen: X509v3 Key Usage: critical Digital Signature, Certificate Sign, CRL Sign Authority Information Access: OCSP - URI:http: CA Issuers - URI:http: X509v3 Authority Key Identifier: keyid:C4:A7:B1:A4: B: C: :FA:DB:E1: B: : :FF:C4: : : : : X509v3 Certificate Policies: Policy: Policy: CPS: http: X509v3 CRL Distribution Points: Full Name: URI:http: X509v3 Subject Key Identifier: A8: A: A: : : D:DD:BA:E6:D1: :B7:A6: : :EF:F3:A8:EC:A1 [...] 3 0x2 0 01 41 42 00 00 01 53 85 73 6 0 85 08 17 16 40 46 2016 17 16 40 46 2021 's Encrypt, CN = Let' 0 //isrg.trustid.ocsp.identrust.com //apps.identrust.com/roots/dstrootcax3.p7c 7 2 71 4 90 75 15 60 85 89 10 2.23 .140 .1 .2 .1 1.3 .6 .1 .4 .1 .44947 .1 .1 .1 //cps.root-x1.letsencrypt.org //crl.identrust.com/DSTROOTCAX3CRL.crl 4 6 63 04 7 39 45 65 Here, the is (the of the previous certificate), and the is . Last, the certificate provided by the organisation is Subject Let's Encrypt Authority X3 Issuer Issuer DST Root CA X3 Digital Signature Trust Co. Certificate: Data: Version: ( ) Serial Number: :af:b0: :d6:a3: :ba: : : : : e:f8: : b Signature Algorithm: sha1WithRSAEncryption Issuer: O = Digital Signature Trust Co., CN = DST Root CA X3 Validity Not Before: Sep : : GMT Not After : Sep : : GMT Subject: O = Digital Signature Trust Co., CN = DST Root CA X3 [...] X509v3 extensions: X509v3 Basic Constraints: critical CA:TRUE X509v3 Key Usage: critical Certificate Sign, CRL Sign X509v3 Subject Key Identifier: C4:A7:B1:A4: B: C: :FA:DB:E1: B: : :FF:C4: : : : : [...] 3 0x2 44 80 27 89 30 39 86 2 40 6 30 21 12 19 2000 30 14 01 15 2021 7 2 71 4 90 75 15 60 85 89 10 As happened for the certificate that we discussed before, this one is self-signed, having the same value for and . Amazon Root CA 1 Subject Issuer How to verify certificates with OpenSSL To verify if a certificate is valid we can use the module of OpenSSL. By default, OpenSSL doesn't trust anything, and relies on a default path in the system to find root certificates. You can see the path running verify verify $ openssl version -d OPENSSLDIR: "/usr/lib/ssl" On Ubuntu 20.04, the directory is a symbolic link to that is installed by the package which is linked to the Mozilla's CA Certificate Program (details on that package can be found in the ). /usr/lib/ssl/certs /etc/ssl/certs ca-certificates source code So, if a root certificate is included in the Mozilla program, it is trusted by OpenSSL $ openssl verify amazon-root-ca-1.pem amazon-root-ca-1.pem: OK while a self-signed certificate is not $ openssl verify self-signed.pem CN = localhost error 18 at 0 depth lookup: self signed certificate error self-signed.pem: verification failed A non-root certificate can be verified specifying which root certificate signed it. So, the certificate for this website is not trusted automatically $ openssl verify www-thedigitalcatonline-com.pem CN = www.thedigitalcatonline.com error 20 at 0 depth lookup: unable to get issuer certificate error www-thedigitalcatonline-com.pem: verification failed local But it is verified specifying the certificate for Let's Encrypt that signed it $ openssl verify -CAfile lets-encrypt-x3.pem www-thedigitalcatonline-com.pem www-thedigitalcatonline-com.pem: OK because the certificate is signed by which is included in the Mozilla program, and thus included in my Linux distribution. lets-encrypt-x3.pem DST_Root_CA_X3.pem If I remove the default certificates path OpenSSL doesn't accept the certificate for Let's Encrypt any more $ openssl verify -no-CApath -CAfile lets-encrypt-x3.pem www-thedigitalcatonline-com.pem C = US, O = Let s Encrypt Authority X3 error 2 at 1 depth lookup: unable to get issuer certificate error www-thedigitalcatonline-com.pem: verification failed 's Encrypt, CN = Let' Low-level certificate validation process Let's have a look at the signature process for x.509 certificates. The process depends on the specific algorithm used to sign the certificate, so I will use the certificate as an example, leaving to the reader the investigation about other algorithms. Amazon Root CA 1 A signed certificate is made of two parts, the certificate itself and the signature. The signature contains an encrypted hash of the certificate. Being encrypted we can verify the signed using their public key, and once we decrypted it we can compare the hash with one that we create on the fly using the same algorithm. For the Amazon root certificate, we know the signature algorithm and value from the output of openssl x509 $ openssl x509 -inform pem - amazon-root-ca-1.pem -noout -text [...] Signature Algorithm: sha256WithRSAEncryption 98:f2:37:5a:41:90:a1:1a:c5:76:51:28:20:36:23:0e:ae:e6: 28:bb:aa:f8:94:ae:48:a4:30:7f:1b: :24:8d:4b:b4:c8:a1: 97:f6:b6:f1:7a:70:c8:53:93:cc:08:28:e3:98:25:cf:23:a4: f9:de:21:d3:7c:85:09:ad:4e:9a:75:3a:c2:0b:6a:89:78:76: 44:47:18:65:6c:8d:41:8e:3b:7f:9a:cb:f4:b5:a7:50:d7:05: 2c:37:e8:03:4b:ad:e9:61:a0:02:6e:f5:f2:f0:c5:b2:ed:5b: b7:dc:fa:94:5c:77:9e:13:a5:7f:52:ad:95:f2:f8:93:3b:de: 8b:5c:5b:ca:5a:52:5b:60:af:14:f7:4b:ef:a3:fb:9f:40:95: 6d:31:54: :42:d3:c7:46:1f:23:ad:d9:0f:48:70:9a:d9:75: 78:71:d1:72:43:34:75:6e:57:59:c2:02:5c:26:60:29:cf:23: 19:16:8e:88:43:a5:d4:e4:cb:08:fb:23:11:43:e8:43:29:72: 62:a1:a9:5d:5e:08:d4:90:ae:b8:d8:ce:14:c2:d0:55:f2:86: f6:c4:93:43:77:66:61:c0:b9:e8:41:d7:97:78:60:03:6e:4a: 72:ae:a5:d1:7d:ba:10:9e:86:6c:1b:8a:b9:59:33:f8:eb:c4: 90:be:f1:b9 in fc fc You can see the signed certificate binary values with . While we can recognise the signature in the last 256 bytes we can't easily separate the bytes with the signature algorithm. If we open the signed certificate with an ASN.1 parser, instead, we can easily find the binary value of the certificate part cat amazon-root-ca-1.pem | tail -n+2 | head -n-1 | base64 -di | hexdump -ve '/1 "%02x "' -e '2/8 "\n"' a0 c cf bf c a e2 f0 a e6 b ca d a f7 d b b d a d a e d a e e d a d a b d a d a e d a e d a f7 d a b2 ca d5 e3 af d e d8 d7 f4 f7 f9 ac d d3 a0 a e b2 a4 d0 ba be d db c8 c f4 ee c7 e eb f5 b5 f8 b0 de d7 b9 d e a4 fe a5 e5 a e4 e1 f9 fd b4 fa da c b fa b0 c a d0 b2 a6 f9 af ec dc a2 f8 ba d5 a9 f9 ee e a3 c0 a1 ba eb a3 c3 f9 dc ff d1 e8 d d d d7 f7 e c4 e bb f2 b8 fa b7 d aa ca b4 f2 e d b f7 c e ff ea cb a ae db fb d b c5 c7 e e1 e0 c8 c d6 c4 c e b e ae c a c8 aa d a3 d ff ff e d ff d d e cc ec bc c e c c7 b2 e a 30 82 03 41 30 82 02 29 03 02 01 02 02 13 06 6 9f 99 8 0 39 78 8 43 96 36 5 30 0 06 09 2 86 48 86 0 01 01 0 05 00 30 39 31 0 30 09 06 03 55 04 06 13 02 55 53 31 0f 30 0 06 03 55 04 0 13 06 41 6 61 7 6f 6 31 19 30 17 06 03 55 04 03 13 10 41 6 61 7 6f 6 20 52 6f 6f 74 20 43 41 20 31 30 1 17 0 31 35 30 35 32 36 30 30 30 30 30 30 5 17 0 33 38 30 31 31 37 30 30 30 30 30 30 5 30 39 31 0 30 09 06 03 55 04 06 13 02 55 53 31 0f 30 0 06 03 55 04 0 13 06 41 6 61 7 6f 6 31 19 30 17 06 03 55 04 03 13 10 41 6 61 7 6f 6 20 52 6f 6f 74 20 43 41 20 31 30 82 01 22 30 0 06 09 2 86 48 86 0 01 01 01 05 00 03 82 01 0f 00 30 82 01 0 02 82 01 01 00 78 80 71 78 71 47 80 50 74 7 6 88 76 99 68 58 21 60 74 84 01 2f 02 2 86 43 7 4 36 01 8 48 07 17 36 4 88 23 3 37 19 49 68 76 38 1 61 9 82 36 4 56 45 16 74 9 9 35 39 2f 20 50 06 6 7 80 47 19 8f 50 38 07 87 39 58 48 67 30 96 94 78 5 6f 89 51 30 86 66 45 66 54 91 48 30 2 7 2 74 70 35 88 24 9 59 6 73 87 17 32 46 28 43 1 9f 24 0 2 4 71 5 5 69 95 02 38 8 50 38 6f 2 62 1 1 54 77 67 0f 9 87 23 3f 40 20 7f 20 80 80 4 3 3 24 26 8 04 6 9 0 02 03 01 00 01 42 30 40 30 0f 06 03 55 1 13 01 01 04 05 30 03 01 01 30 0 06 03 55 1 0f 01 01 04 04 03 02 01 86 30 1 06 03 55 1 0 04 16 04 14 84 18 85 34 0 94 94 2 08 59 9 10 4 0 08 The signature algorithm part is a f7 b 30 0d 06 09 2 86 48 86 0d 01 01 0 05 00 03 82 01 01 00 and the ASN.1 parser tells us that those bytes represent an which value is . Now, object identifiers are not complicated per se, they are just a way to identify algorithms and other well known components in ASN.1 structures. The description of the field of an x.509 certificate mentions three other RFCs that contains descriptions of the available algorithms. In particular, contains the description of PKCS #1 one-way hash functions, one of which is OBJECT IDENTIFIER 2.16.840.1.101.3.4.2.1 signatureAlgorithm RFC 4055 - ::= { - - - id sha256 OBJECT IDENTIFIER joint iso itu ( ) t 2 ( ) ( ) ( ) ( ) country 16 us 840 organization 1 gov 101 ( ) ( ) ( ) } csor 3 nistalgorithm 4 hashalgs 2 1 You can see the values in the object identifier between parentheses. Since these are PKCS #1 (a.k.a. RSA) has functions, OpenSSL identifies it as (see again ). sha256WithRSAEncryption RFC 4055 RSA encryption is described in ("PKCS #1: RSA Encryption Version 1.5") and the signature algorithm based on RSA is described there in . In particular, section 10.2 details the verification process, which is the one we are interested in. The steps are RFC 2313 section 10 Bit-string-to-octet-string conversion of the signature RSA decryption Digest decoding (ASN.1) Message digesting and comparison As for the signature conversion, the sentence Specifically, assuming that the length bits the signature S a multiple eight, the first the signature shall become the most significant the first octet the data, so through the last the signature, which shall become the least significant the last octet the data. in of is of bit of bit of of encrypted and on bit of bit of of encrypted is a very verbose way to say that the signature is big-endian. So, the hexadecimal value of the signature is f a a ac eaee bbaaf ae a f bfc d bb a f b f a cf a f de d ad a ac b a d b f acbf b a d bad e a ef f f b ed bb dcfa a f ad f f bde b bca a b af f befa fb f d fc d f f a d d cf a d cb fb a a d d aeb d ce d f f b d a aea d dba b ab f ebc bef b 98 2375 4190 11 57651282036230 628 894 48 4307 1 248 4 4 c 8 197 6 6 17 70 c 85393 cc 0828e39825 23 4 9 21 37 c 8509 4e9 753 20 6 897876444718656 c 8 418e3 7 9 4 5 750 7052 c 37e8034 961 0026 5 2 0 c 5 2 5 7 945 c 779e13 57 52 95 2 8933 8 5 c 5 5 525 60 14 74 3 9 40956 3154 42 3 c 7461 23 add 90 48709 9757871 1724334756e5759 c 2025 c 266029 2319168e8843 5 4e4 08 23 1143e843297262 1 95 5e08 490 8 8 14 c 2 055 286 6 c 49343776661 c 0 9e841 7977860036e4 72 5 17 109e866 c 1 8 95933 8 490 1 9 And reading the field of the certificate we find the public key. Remember that this is a root certificate, so it is signed using the same key that it contains, which is not true in general. Subject Public Key Info The public key's modulus is b ca d af d ed d f f f f ac d d a a eb a d ba be ddb cf ee eeb f b f b ded b d ea fe a a e f fdb fa da b ffab ad b a f afec f dca f bad a f ee f a a ba eba f dc ffd d d d d f ec ebb f b fab daa cab f f d bf ffea cb aae fdbfb d bc e e f d f f b ae ac aa d 2788071 78 5e371 478050747 6 8 78876 49968 7582160 97484012 022 86 3 0437 4 2 4 036 01 8 48 c 80717364 4 8823 c 73 37 5 519 84968 0 7 976381 619 4 8236 5e54 56e445 1 9 416 74 9 c 9 35392 02050066 c 7 080 2 6 9 47198 503807 2873958 8 5 9 948673096 94785e6 89 351 c 0308666 14566 54 3 c 391 948 1e8302 7 2 747035 78824 79 4596 738717 2324628 843 71 4 29 240e2 4 7715 c 5e69 9502 388 50386 2 621 5 c 71 54e177 067 c 80 9 c 8723 63 40207 2080 c 4804 c 3e3 24268e04 6 c 9 8 0 and the exponent is (default choice). 0x10001 RSA public-key signature decryption is performed with , and this operation returns signature ^ exponent mod modulus ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff fffffffffffffffffffff003031300d0609608648016503040201050004206fc b8ac3d2b52c08baf56255e43d22c762962e4facab01ace16d48ec008be0a 1f 4 Once the padding is removed, we are left with an ASN.1 binary structure that represents the digest ::= SEQUENCE { } DigestInfo digestAlgorithm DigestAlgorithmIdentifier, digest Digest (see ) RFC 2313 - Section 10.1.2 The value of can be extracted with an ASN.1 parser or by taking the last 256 bits and is . Digest 6fc4b8ac3d2b52c08baf56255e43d22c762962e4facab01ace16d48ec008be0a At this point we need to process the certificate bytes (without signature) with the SHA-256 hash function and we will find a matching value of . 6fc4b8ac3d2b52c08baf56255e43d22c762962e4facab01ace16d48ec008be0a This process (for the specific case of this certificate) can be easily done in Python cryptography x509 hashlib sha256 certificate_pem_file = open(certificate_pem_file, ) f: certificate_pem = f.read() certificate = x509.load_pem_x509_certificate(certificate_pem) modulus = certificate.public_key().public_numbers().n exponent = certificate.public_key().public_numbers().e signature = int.from_bytes(certificate.signature, ) verification = pow(signature, exponent, modulus) digest = bytes().fromhex(str(hex(verification))[ :]) calculated_digest = sha256(certificate.tbs_certificate_bytes) print(digest.hex() == calculated_digest.hexdigest()) from import from import "amazon-root-ca-1.pem" with "rb" as "big" -64 This is arguably not the best Python code ever, but it's a simple way to demonstrate the process. As I said, this is far from being general, as it assumes the signature is , which might not be the case. sha256WithRSAEncryption What I showed you here is what happens when we validate a root certificate. When we validate a non-root certificate the process is exactly the same (taking into account that the algorithms involved might be different), only the public key used to sign the certificate doesn't come from the certificate itself, but from the signer one. So, in the case of this blog, the certificate for www.thedigitalcat.com has a signature encrypted with the public key of Let's Encrypt. And the certificate for Let's Encrypt will be signed using the public key of Digital Signature Trust Co. This is what creates the chain of trust. Algorithms used by root certificates A quick scan of the certificates that are part of the Mozilla program reveals that the vast majority of them is using RSA to self-sign them $ i /etc/ssl/certs/*.pem; openssl x509 -inform pem - -noout -text | grep -E ; | sort | uniq -c 25 Public Key Algorithm: id-ecPublicKey 114 Public Key Algorithm: rsaEncryption for in do in ${i} "Public Key Algorithm" done while part of them are using which is the identifier of elliptic curves algorithms. id-ecPublicKey When it comes to signature algorithms, instead, there is more variety $ i /etc/ssl/certs/*.pem; openssl x509 -inform pem - -noout -text | grep -E ; | sort | uniq -c 7 Signature Algorithm: ecdsa-with-SHA256 18 Signature Algorithm: ecdsa-with-SHA384 47 Signature Algorithm: sha1WithRSAEncryption 57 Signature Algorithm: sha256WithRSAEncryption 9 Signature Algorithm: sha384WithRSAEncryption 1 Signature Algorithm: sha512WithRSAEncryption for in do in ${i} "^ Signature Algorithm" done Even here, elliptic curves are slowly being adopted. AWS components related to certificates If you are using AWS, you can create certificates with ACM, the . Such certificates cannot be downloaded, they can only be attached to other AWS components. For this reason, the generation process reuire you to create any request, as you might have to do with other authorities. Certificates created in the ACM are free. AWS Certificate Manager Certificates created in the ACM can be attached to several AWS components, most notably , , and . Load Balancers CloudFront API Gateway Traditionally, load balancers are the place where TLS is terminated for HTTPS, requiring a connection to port 443. While can do that, in 2019 AWS support for certificates in as well. Application Load Balancers announced Network Load Balancers Let's encrypt In an effort to push for HTTP encryption of any public server, the Internet Security Research Group founded in 2016 a non-profit CA named , which provides at no charge TLD certificates valid for 90 days. Such certificates can be renewed automatically as part of the setup ( ) and represent a viable alternative to certificates issued by other CA, in particular for open source projects. This blog uses a certificate issued by Let's Encrypt (provided by GitHub Pages) and will thus expire in less than 3 months (but also automatically renewed). Let's Encrypt certbot Final words I hope this post helped to clarify some of the most obscure points of certificates, that definitely bugged be when I first approached them. As always when standards are involved, the risk is to get lost in the myriad of documents where information is scattered, and not to realise that some (if not many) parts of the systems we run every day have a long history and thus a big burden of legacy code or nomenclature. Resources The Wikipedia article on . TLS The Wikipedia article on The Wikipedia article on Certificate authority X.509 The Wikipedia article on Let's Encrypt OpenSSL documentation: , , asn1parse x509 verify The Abstract Syntax Notation One interface description language ASN.1 - "PKCS #1: RSA Encryption Version 1.5" RFC 2313 - "Internet X.509 Public Key Infrastructure Certificate and CRL Profile" RFC 2459 - "Algorithms and Identifiers for the Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile" RFC 3279 - "Additional Algorithms and Identifiers for RSA Cryptography for use in the Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile" RFC 4055 - "Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile" RFC 5280 - "Object Identifier Registry for the PKIX Working Group" RFC 7299 - "Textual Encodings of PKIX, PKCS, and CMS Structures" RFC 7468 - "PKCS #1: RSA Cryptography Specifications Version 2.2" RFC 8017 - "The Transport Layer Security (TLS) Protocol Version 1.3" RFC 8446 - The Python pyca/cryptography package pyca/cryptography Previously published at https://www.thedigitalcatonline.com/blog/2020/11/04/public-key-cryptography-ssl-certificates/