[{"data":1,"prerenderedAt":1190},["ShallowReactive",2],{"nav_featured_podcast":3,"nav_featured_press_release":21,"navigation_content":30,"engineering_blog_post:pki-cert-management":378},{"uid":4,"title":5,"episodeLabel":6,"dateLabel":7,"episodeArt":8,"href":20},"from-payment-rails-to-connectivity","From Payment Rails to Connectivity, with The Clearing House's David Watson","EPISODE 5","August 18, 2026",{"dimensions":9,"alt":12,"copyright":13,"url":14,"id":15,"edit":16},{"width":10,"height":11},1064,652,"Payments Cannot Fail — Episode 05 with David Watson",null,"\u002F_prismic-media\u002Fd80df2e47c3ecb6f-cFcyPAgzKCMQEaND_Episode-05-David.jpg","cFcyPAgzKCMQEaND",{"x":17,"y":17,"zoom":18,"background":19},0,1,"transparent","\u002Fresources\u002Fpodcasts\u002Ffrom-payment-rails-to-connectivity",{"uid":22,"title":23,"tag":24,"dateLabel":25,"imageUrl":26,"imageAlt":27,"href":28,"imageFit":29},"form3-expands-strategic-partnership-with-sumup","Form3 expands strategic partnership with SumUp to bring real-time SEPA payments to millions of European small businesses","EU","February 25, 2026","\u002F_prismic-media\u002F3e91177f91478610-QA44Gzev0_tdg3ZI_SumUp.jpg","sumup","\u002Fresources\u002Fpress-releases\u002Fform3-expands-strategic-partnership-with-sumup","cover",{"header":31,"platform":59,"solutions":91,"developers":133,"company":155,"resources":184,"partnerships":208,"footer":220,"mobile":325},{"ctaLabel":32,"ctaHref":33,"topNav":34},"TALK TO OUR TEAM","\u002Fcontact",[35,39,43,47,51,55],{"label":36,"href":37,"key":38},"Platform","\u002Fplatform","platform",{"label":40,"href":41,"key":42},"Solutions","\u002Fsolutions","solutions",{"label":44,"href":45,"key":46},"Developers","\u002Fdevelopers","developers",{"label":48,"href":49,"key":50},"Company","\u002Fcompany","company",{"label":52,"href":53,"key":54},"Resources","\u002Fresources","resources",{"label":56,"href":57,"key":58},"Partnerships","\u002Fpartnerships","partnerships",{"sectionEyebrow":60,"primary":61,"productLinks":65,"enterprise":81,"trustFabric":86},"Explore the Platform",{"heading":62,"body":63,"ctaLabel":64,"ctaHref":37},"Our Payments Platform","A resilient, cloud-native platform powering real-time account-to-account payments at global scale.","See How It Works",[66,69,72,75,78],{"label":67,"href":68},"Payments Processing & Gateway","\u002Fpayments-processing-gateway",{"label":70,"href":71},"Orchestration & Intelligent Routing","\u002Forchestration-intelligent-routing",{"label":73,"href":74},"Payments Simulator","\u002Fpayments-simulator",{"label":76,"href":77},"Sponsor Bank Enablement","\u002Fsponsor-bank-enablement",{"label":79,"href":80},"Informed UI","\u002Finformed-ui",{"heading":82,"body":83,"ctaLabel":84,"ctaHref":85},"Form3 Enterprise","Deploy and manage proven cloud-native payments technology in the environment that works for your institution.","Deploy Enterprise","\u002Fplatform\u002Fenterprise",{"heading":87,"body":88,"ctaLabel":89,"ctaHref":90},"Form3 Trust Fabric","Manage TLS certificates, cryptographic vulnerabilities and quantum readiness at scale, with continuous visibility.","Deploy Trust Fabric","\u002Fplatform\u002Ftrust-fabric",{"regionsIntro":92,"regions":98,"industries":118},{"eyebrow":93,"heading":94,"headingLine2":95,"body":96,"ctaLabel":64,"ctaHref":97},"Regions","Global Reach.","Regional Expertise.","A proven payments platform serving organizations worldwide, with specialized experience across North America, United Kingdom, and Europe.","\u002Fglobal",[99,108,113],{"label":100,"description":101,"ctaLabel":102,"href":103,"extraLinks":104},"North America","Real-time infrastructure, through a resilient, multi-cloud platform built for scale and regulatory confidence.","US HOME","\u002Fsolutions\u002Funited-states",[105],{"label":106,"href":107},"CANADA HOME","\u002Fsolutions\u002Fcanada",{"label":109,"description":110,"ctaLabel":111,"href":112},"United Kingdom","Powering account-to-account payments at the heart of the UK financial ecosystem, with proven resilience.","UK HOME","\u002Fsolutions\u002Funited-kingdom",{"label":114,"description":115,"ctaLabel":116,"href":117},"Europe","Enabling secure, real-time and SEPA payments across European markets through a unified, cloud-native platform.","EUROPE HOME","\u002Fsolutions\u002Feurope",{"eyebrow":119,"links":120},"Industries",[121,125,129],{"label":122,"href":123,"iconSrc":124},"Financial Services","\u002Fsolutions\u002Findustries\u002Ffinancial-services","\u002F_prismic-media\u002F29c09c45caa89db9-kbUHZmgTmuIMbo1t_FinancialServices_menu.svg",{"label":126,"href":127,"iconSrc":128},"Fintech","\u002Fsolutions\u002Findustries\u002Ffintech","\u002F_prismic-media\u002F6de3e7cb4dd8d874-SjwNe6Nh-bbuTi0P_Fintech_menu.svg",{"label":130,"href":131,"iconSrc":132},"Government","\u002Fsolutions\u002Findustries\u002Fgovernment","\u002F_prismic-media\u002Fe71bc3a74a1d2142-kaGgdituzKDnVTbm_Government_menu.svg",{"engineering":134,"api":142,"pressEyebrow":154},{"eyebrow":135,"links":136},"Engineering",[137,139],{"label":135,"href":138},"\u002Fengineering",{"label":140,"href":141},"Accreditations","\u002Faccreditations",{"eyebrow":143,"links":144},"API",[145,148,151],{"label":146,"href":147},"API Docs","https:\u002F\u002Fwww.api-docs.form3.tech\u002F",{"label":149,"href":150},"API Tutorials","https:\u002F\u002Fwww.api-docs.form3.tech\u002Fapi\u002Ftutorials\u002Fgetting-started\u002Fintroduction",{"label":152,"href":153},"API Status","https:\u002F\u002Fstatus.form3.tech\u002F","Latest Press Release",{"about":156,"people":171,"podcastEyebrow":183},{"eyebrow":157,"links":158},"About",[159,162,165,168],{"label":160,"href":161},"Our Story","\u002Fcompany\u002Four-story",{"label":163,"href":164},"Our Team","\u002Fcompany\u002Fteam",{"label":166,"href":167},"Our Success & Strategic Approach","\u002Fcompany\u002Four-success",{"label":169,"href":170},"Customer Stories","\u002Fcompany\u002Fcustomer-stories",{"eyebrow":172,"links":173},"People",[174,177,180],{"label":175,"href":176},"Careers","\u002Fcompany\u002Fcareers",{"label":178,"href":179},"Vacancies","\u002Fcompany\u002Fvacancies",{"label":181,"href":182},"Culture","\u002Fcompany\u002Fculture","Latest Podcast",{"intro":185,"links":189,"pressEyebrow":154,"podcastEyebrow":183},{"eyebrow":52,"heading":186,"body":187,"ctaLabel":188,"ctaHref":53},"Form3 Resources","Our Resources bring together thought leadership, engineering insights, payments expertise, webinars, podcasts, whitepapers, company news and stories from our teams—all in one place.","LEARN MORE",[190,193,196,199,202,205],{"label":191,"href":192},"Payments Cannot Fail Podcast","\u002Fresources\u002Fpodcasts",{"label":194,"href":195},"Press Releases","\u002Fresources\u002Fpress-releases",{"label":197,"href":198},"Payment Insights","\u002Fresources\u002Fpayment-insights",{"label":200,"href":201},"Culture Blog","\u002Fresources\u002Fculture-blog",{"label":203,"href":204},"Engineering Blog","\u002Fresources\u002Fengineering-blog",{"label":206,"href":207},"Events","\u002Fevents",{"intro":209,"links":213,"pressEyebrow":154},{"eyebrow":56,"heading":210,"body":211,"ctaLabel":212,"ctaHref":57},"Partner with Form3","Explore how Form3 works with banks, fintechs, cloud providers, technology platforms and system integrators to accelerate payment modernization, strengthen customer offerings and unlock new opportunities for growth.","Let's Partner Together",[214,217],{"label":215,"href":216},"Technical & Ecosystem Partners","\u002Fpartnerships\u002Ftechnical-ecosystem",{"label":218,"href":219},"Channel & Distribution Partners","\u002Fpartnerships\u002Fchannel-distribution",{"platform":221,"region":229,"development":240,"company":248,"resources":259,"partnerships":267,"stayConnected":272,"legalLinks":292,"certifications":314},{"title":36,"links":222},[223,224,225,226,227,228],{"label":62,"href":37},{"label":67,"href":68},{"label":70,"href":71},{"label":73,"href":74},{"label":76,"href":77},{"label":79,"href":80},{"title":230,"links":231},"Region",[232,234,236,237,238],{"label":233,"href":97},"Global",{"label":235,"href":103},"United States",{"label":109,"href":112},{"label":114,"href":117},{"label":239,"href":107},"Canada",{"title":241,"links":242},"Development",[243,244,245,246,247],{"label":135,"href":138},{"label":140,"href":141},{"label":146,"href":147},{"label":149,"href":150},{"label":152,"href":153},{"title":48,"links":249},[250,251,252,253,254,255,256],{"label":160,"href":161},{"label":163,"href":164},{"label":169,"href":170},{"label":175,"href":176},{"label":178,"href":179},{"label":181,"href":182},{"label":257,"href":258},"Net Zero","\u002Fcompany\u002Fnet-zero",{"title":52,"links":260},[261,262,263,264,265,266],{"label":186,"href":53},{"label":191,"href":192},{"label":194,"href":195},{"label":200,"href":201},{"label":203,"href":204},{"label":206,"href":207},{"title":56,"links":268},[269,270,271],{"label":210,"href":57},{"label":215,"href":216},{"label":218,"href":219},{"title":273,"body":274,"ctaLabel":32,"ctaHref":33,"social":275},"Stay Connected","Form3 is a global account-to-account financial fabric delivering a proven payments platform trusted by banks and fintechs to deliver resilient, real-time payment experiences for their customers at scale.",[276,280,284,288],{"label":277,"href":278,"icon":279},"LinkedIn","https:\u002F\u002Fwww.linkedin.com\u002Fcompany\u002Fform3-financial-cloud\u002F","linkedin",{"label":281,"href":282,"icon":283},"X","https:\u002F\u002Fwww.x.com\u002FForm3Cloud","x",{"label":285,"href":286,"icon":287},"YouTube","https:\u002F\u002Fwww.youtube.com\u002F@Form3Cloud","youtube",{"label":289,"href":290,"icon":291},"Instagram","https:\u002F\u002Fwww.instagram.com\u002Fform3.tech","instagram",[293,296,299,302,305,308,311],{"label":294,"href":295},"Terms & Conditions","\u002Flegal\u002Fterms-and-conditions",{"label":297,"href":298},"Privacy Policy","\u002Flegal\u002Fdata-privacy-statement",{"label":300,"href":301},"Recruitment Data Policy","\u002Flegal\u002Frecruitment-data-policy",{"label":303,"href":304},"Modern Slavery Statement","\u002Flegal\u002Fmodern-slavery",{"label":306,"href":307},"License","\u002Flegal\u002Flicense",{"label":309,"href":310},"Cookie Policy","\u002Flegal\u002Fcookie-policy",{"label":312,"href":313},"Manage Cookies","#cookies",[315,317,319,321,323],{"label":316},"ISO 27001",{"label":318},"ISO 27017",{"label":320},"ISO 27018",{"label":322},"ISAE 3000 SOC 2 Type II",{"label":324},"ISO 22301",{"platform":326,"solutions":341,"developers":355,"company":365,"resources":366,"partnerships":374},[327,329,339,340],{"kind":328,"label":62,"href":37},"link",{"kind":330,"label":60,"children":331},"group",[332,333,334,335,337],{"label":67,"href":68},{"label":70,"href":71},{"label":73,"href":74},{"label":76,"href":336},"\u002Fplatform\u002Fsponsor-bank-enablement",{"label":79,"href":338},"\u002Fplatform\u002Finform3d-ui",{"kind":328,"label":82,"href":85},{"kind":328,"label":87,"href":90},[342,344,350],{"kind":328,"label":233,"href":343},"\u002Fsolutions\u002Fglobal",{"kind":330,"label":93,"children":345},[346,347,348,349],{"label":235,"href":103},{"label":239,"href":107},{"label":109,"href":112},{"label":114,"href":117},{"kind":330,"label":119,"children":351},[352,353,354],{"label":122,"href":123},{"label":126,"href":127},{"label":130,"href":131},[356,360],{"kind":330,"label":135,"children":357},[358,359],{"label":135,"href":138},{"label":140,"href":141},{"kind":330,"label":143,"children":361},[362,363,364],{"label":146,"href":147},{"label":149,"href":150},{"label":152,"href":153},[],[367,368,369,370,371,372,373],{"kind":328,"label":186,"href":53},{"kind":328,"label":191,"href":192},{"kind":328,"label":194,"href":195},{"kind":328,"label":197,"href":198},{"kind":328,"label":200,"href":201},{"kind":328,"label":203,"href":204},{"kind":328,"label":206,"href":207},[375,376,377],{"kind":328,"label":210,"href":57},{"kind":328,"label":215,"href":216},{"kind":328,"label":218,"href":219},{"id":379,"uid":380,"url":381,"type":382,"href":383,"tags":384,"first_publication_date":385,"last_publication_date":386,"slugs":387,"linked_documents":389,"lang":390,"alternate_languages":391,"data":392},"alz1BBEAACsAUWdw","pki-cert-management","\u002Fresources\u002Fengineering-blog\u002Fpki-cert-management","engineering_blog_post","https:\u002F\u002Fform3-website.cdn.prismic.io\u002Fapi\u002Fv2\u002Fdocuments\u002Fsearch?ref=apnMZxEAACcAKWxv&q=%5B%5B%3Ad+%3D+at%28document.id%2C+%22alz1BBEAACsAUWdw%22%29+%5D%5D",[],"2026-07-19T16:21:55+0000","2026-08-27T02:06:56+0000",[388],"overview",[],"en-us",[],{"title":393,"excerpt":394,"card_image":395,"published_date":401,"reading_time":402,"tag":403,"dek":394,"featured_image":404,"about_form3":411,"client_about_heading":13,"client_about_body":412,"author_name":413,"author_title":414,"author_photo":415,"author_bio":423,"author_linkedin":436,"slices":439,"meta_title":393,"meta_description":394},"PKI certificate management","I have a rough understanding of PKI certificates, how they work, and what TLS is in general. However, I've always struggled to understand the details, particularly from the point of view of an operator. How do I check if a certificate is valid? How do I check who issued it? What does it even mean to \"issue\" a certificate? To make matters worse, I'm frequently confounded by the variety of different file types used for certificates. Is it a pem, or a crt, or a pub? Speaking of pub, what's the difference between the TLS certificate my server uses to encrypt traffic, and the certificates I use for SSH authentication? In this post, I will answer these questions and then walk though a practical example of using certificates for TLS via a local nginx proxy, modeling the client\u002Fserver TLS you often see on the web.",{"dimensions":396,"alt":393,"copyright":13,"url":398,"id":399,"edit":400},{"width":397,"height":397},800,"\u002F_prismic-media\u002F64456a87781169bc-exE9iXmqKY6s8eet_pki-cert-management.png","exE9iXmqKY6s8eet",{"x":17,"y":17,"zoom":18,"background":19},"2022-08-05",6,"Blogs",{"dimensions":405,"alt":13,"copyright":13,"url":408,"id":409,"edit":410},{"width":406,"height":407},1200,627,"\u002F_prismic-media\u002F66ea9aa6b457dac7--yOjR3yIUzRrs2MA_fcbdb2ff-9078-46dd-8b14-191a29f.png","-yOjR3yIUzRrs2MA",{"x":17,"y":17,"zoom":18,"background":19},[],[],"Andy Kuszyk","Staff Engineer",{"dimensions":416,"alt":413,"copyright":13,"url":419,"id":420,"edit":421},{"width":417,"height":418},317,473,"\u002F_prismic-media\u002Fc371d17a59432918-GFOBoL2Tovd3zPoj_27d09fad-dd24-483c-92fc-1ac2a07.jpeg","GFOBoL2Tovd3zPoj",{"x":17,"y":17,"zoom":18,"background":422},"#ffffff",[424],{"type":425,"text":426,"spans":427},"paragraph","Andy Kuszyk is a Staff Engineer at Form3, based in Southampton. He's been working as a software engineer for 8 years with a variety of technologies, including .NET, Python and most recently Go. Check out more of his tech articles on his blog.",[428],{"start":429,"end":430,"type":431,"data":432},233,241,"hyperlink",{"link_type":433,"url":434,"target":435},"Web","http:\u002F\u002Fandykuszyk.github.io\u002F","_blank",{"link_type":433,"key":437,"url":438,"target":435},"9894a13a-2eef-4ffd-a6dc-a1a685041efd","https:\u002F\u002Fwww.linkedin.com\u002Fcompany\u002Fandy-kuszyk",[440,481,507,549,569,583,593,607,615,662,670,678,686,694,702,710,718,726,734,760,768,776,784,792,800,826,834,848,856,876,884,892,900,908,922,939,947,957,965,976,984,992,1000,1008,1016,1027,1035,1043,1050,1061,1068,1076,1084,1092,1100,1108,1116,1124,1132,1148,1156,1167],{"variation":441,"version":442,"items":443,"primary":444,"id":479,"slice_type":480,"slice_label":13},"default","initial",[],{"body":445},[446,450,457,460,464,467,470,473,476],{"type":447,"text":448,"spans":449},"heading2","Overview",[],{"type":425,"text":451,"spans":452},"As I said, I have a very rough understanding, but a lot of gaps.",[453],{"start":454,"end":455,"type":456},25,30,"em",{"type":425,"text":458,"spans":459},"In this post, I will try to explain:",[],{"type":461,"text":462,"spans":463},"list-item","The different file formats that can be used to store certificates.",[],{"type":461,"text":465,"spans":466},"How the files are structured, and how they differ from one another.",[],{"type":461,"text":468,"spans":469},"How to generate new certificates, and inspect existing ones, using the openssl command line tool.",[],{"type":461,"text":471,"spans":472},"What a certificate chain is, and how to inspect it.",[],{"type":461,"text":474,"spans":475},"The difference between a TLS certificate and an SSH certificate.",[],{"type":425,"text":477,"spans":478},"Hopefully by the end of the post, you'll have a clearer idea of what certificates are, and how to interact with them.",[],"rich_text$39ac6984-4191-4a9d-9d67-95698efc813b","rich_text",{"variation":441,"version":442,"items":482,"primary":483,"id":506,"slice_type":480,"slice_label":13},[],{"body":484},[485,488,491,494,497,500,503],{"type":447,"text":486,"spans":487},"An introduction to PKI certificates",[],{"type":425,"text":489,"spans":490},"Before we start exploring the different ways PKI certificates can be generated, stored, verified, and used, let's just take a step back and start with an introduction to PKI certificates in general.",[],{"type":425,"text":492,"spans":493},"Public Key Infrastructure certificates are most commonly used for securing TCP and HTTP communication via TLS. They are primarily used to:",[],{"type":461,"text":495,"spans":496},"Encrypt end-to-end communication.",[],{"type":461,"text":498,"spans":499},"Establish trust between a client and a server, so that the server's identity can be verified.",[],{"type":425,"text":501,"spans":502},"The certificates themselves normally contain metadata about the owner (such as name, location, etc.), as well as a public key used for encryption. The certificate is accompanied by a private key, which makes decryption possible.",[],{"type":425,"text":504,"spans":505},"Normally, a PKI certificate manifests as a pair of files on disk. One containing the certificate, and another containing the private key.",[],"rich_text$d6884baf-fae5-43bc-bd33-09c7c712aa7a",{"variation":441,"version":442,"items":508,"primary":509,"id":548,"slice_type":480,"slice_label":13},[],{"body":510},[511,514,517,520,524,527,530,533],{"type":447,"text":512,"spans":513},"PKI certificate files",[],{"type":425,"text":515,"spans":516},"Most TLS certificates are in fact X.509 certificates. X.509 is a standard for certificate structure which defines which fields are included in the certificate. X.509 certificates can be stored in a variety of different file formats, which is the main cause of my confusion about which file types are used to store certificates.",[],{"type":425,"text":518,"spans":519},"The certificate itself is comprised of three parts:",[],{"type":521,"text":522,"spans":523},"o-list-item","Information about the certificate, such as the issuer and the distinguished name the certificate is for.",[],{"type":521,"text":525,"spans":526},"The public key, used for encrypting data.",[],{"type":521,"text":528,"spans":529},"The private key, used for decrypting data.",[],{"type":425,"text":531,"spans":532},"Normally, when a certificate is generated, its information and public key are stored in one file (normally just referred to as the certificate), and the private key is stored in another file.",[],{"type":425,"text":534,"spans":535},"X.509 certificates are typically stored in base64 encoded ASCII files which use the *.pem, *.crt and *.cer file extensions for the public key portion interchangeably. The private key is typically stored in a file with the *.key file extension. Whenever you see one of these files, you're looking at a base64 encoded X.509 certificate, irrespective of what the file extension might be.",[536,539,542,545],{"start":537,"end":538,"type":456},84,89,{"start":540,"end":541,"type":456},91,96,{"start":543,"end":544,"type":456},101,106,{"start":546,"end":547,"type":456},222,227,"rich_text$fc069231-87b7-497d-8a89-3e7abb05541d",{"variation":441,"version":442,"items":550,"primary":551,"id":568,"slice_type":480,"slice_label":13},[],{"body":552},[553,556,559,562,565],{"type":447,"text":554,"spans":555},"Certificate requests",[],{"type":425,"text":557,"spans":558},"Before we dive into generating new certificates in the next section, it's worth briefly mentioning what a certificate request is. Certificate requests require a basic understanding of certificate authorities.",[],{"type":425,"text":560,"spans":561},"A certificate authority is a reputable company who digitally signs certificates to indicate that they are from a trustworthy source. When a certificate is used for authentication and encryption, its authenticity can be verified by checking that the certificate's signature was generated by the original certificate authority. This verification process is discussed in more detail later in this post.",[],{"type":425,"text":563,"spans":564},"Normally, when a new certificate is generated, it is signed by a certificate authority. When generating certificates in this way, the artifacts of the certificate generation process are files which actually represent a certificate request, and not a certificate.",[],{"type":425,"text":566,"spans":567},"The certificate request is sent to the certificate authority, who returns a signed certificate which is ready to use. When experimenting with certificate generation locally, this certificate request and signing step can be skipped, and a certificate can be generated directly with no signing. This is known as a self-signed certificate, which is perfectly usable, but would fail certificate verification checks as no trusted authority has signed it. More on this later.",[],"rich_text$e7620f60-0611-4ee0-8960-1ae33d6e06ec",{"variation":441,"version":442,"items":570,"primary":571,"id":582,"slice_type":480,"slice_label":13},[],{"body":572},[573,576,579],{"type":447,"text":574,"spans":575},"Generating and inspecting certificates with openssl",[],{"type":425,"text":577,"spans":578},"New X.509 certificates can be generated using the openssl command line tool. Parameters for certificate generation can be provided via command line arguments, interactive responses, or via a config file.",[],{"type":425,"text":580,"spans":581},"For this example, we will start with the following config file:",[],"rich_text$6572940c-f24e-46c7-8f22-4374250f6193",{"variation":441,"version":442,"items":584,"primary":585,"id":591,"slice_type":592,"slice_label":13},[],{"language_label":13,"code":586},[587],{"type":588,"text":589,"spans":590},"preformatted","$ cat \u003C\u003C EOF > openssl.conf\n[req]\ndistinguished_name=distinguished_name\nprompt=no\n\n[distinguished_name]\ncountryName=UK\nlocalityName=London\norganizationName=Form3\ncommonName=localhost\nEOF",[],"code_block$36802fca-8717-4d69-803f-5ac289588abf","code_block",{"variation":441,"version":442,"items":594,"primary":595,"id":606,"slice_type":480,"slice_label":13},[],{"body":596},[597,603],{"type":425,"text":598,"spans":599},"The distinguished name in this configuration identifies the owner of the certificate. As well as containing things like organisation name and location, the distinguished name also includes the Common Name. This is the hostname at which the certificate will be used, and forms an important part of certificate verification. In this case, the certificate we're generating could only be used to encrypt traffic on localhost.",[600],{"start":601,"end":602,"type":456},411,420,{"type":425,"text":604,"spans":605},"Then, we can use openssl to generate a new X.509 certificate with the following:",[],"rich_text$9ca6ceda-5800-4cb1-85dd-0005470b5a74",{"variation":441,"version":442,"items":608,"primary":609,"id":614,"slice_type":592,"slice_label":13},[],{"language_label":13,"code":610},[611],{"type":588,"text":612,"spans":613},"$ openssl req -x509 -nodes -newkey rsa:4096 -keyout private.key -out certificate.pem -config openssl.conf",[],"code_block$b092b2ce-9327-43f6-84db-c10ad03fd960",{"variation":441,"version":442,"items":616,"primary":617,"id":661,"slice_type":480,"slice_label":13},[],{"body":618},[619,622,627,632,636,641,646,651,655,658],{"type":425,"text":620,"spans":621},"Let's just examine each of the command line arguments:",[],{"type":461,"text":623,"spans":624},"req: this command creates and processes certificate requests.",[625],{"start":17,"end":626,"type":456},3,{"type":461,"text":628,"spans":629},"-x509: generate an X.509 certificate that is self-signed, as opposed to a certificate request that would need to be signed by a certificate authority.",[630],{"start":17,"end":631,"type":456},5,{"type":461,"text":633,"spans":634},"-nodes: do not encrypt the private key.",[635],{"start":17,"end":402,"type":456},{"type":461,"text":637,"spans":638},"-newkey rsa:4096: indicates that a new certificate request and private key should be generated, and that the RSA algorithm should be used with a key length of 4096 bits.",[639],{"start":17,"end":640,"type":456},16,{"type":461,"text":642,"spans":643},"-keyout private.key: the file to write the private key to.",[644],{"start":17,"end":645,"type":456},19,{"type":461,"text":647,"spans":648},"-out certificate.pem: the file to write the certificate and public key to.",[649],{"start":17,"end":650,"type":456},20,{"type":461,"text":652,"spans":653},"-config openssl.conf: the config file to use for certificate parameters.",[654],{"start":17,"end":650,"type":456},{"type":425,"text":656,"spans":657},"The result of this command is two files: a private key, and a certificate file containing a public key.",[],{"type":425,"text":659,"spans":660},"The certificate looks like this:",[],"rich_text$f1b941c6-60c6-4cf0-8d01-adeb440cdf78",{"variation":441,"version":442,"items":663,"primary":664,"id":669,"slice_type":592,"slice_label":13},[],{"language_label":13,"code":665},[666],{"type":588,"text":667,"spans":668},"$ cat certificate.pem\n-----BEGIN CERTIFICATE-----\nMIIE2DCCAsACCQCZfiGwlnUbgDANBgkqhkiG9w0BAQsFADAuMQswCQYDVQQGEwJV\nSzEPMA0GA1UEBwwGTG9uZG9uMQ4wDAYDVQQKDAVGb3JtMzAeFw0yMjA0MjcxNTU1\n...\nqjgSTJpltmuAUl2qYvo8ZV9RFnhUKPk3e1ntJMWA1rvhaHaClTLUK9hUTGVuj\u002FeL\n5xNkbEKS\u002FbwwCJQNdmgdyKeTa7ntJYdxiXMClemcJZiFQup3WBtWzEueaxI=\n-----END CERTIFICATE-----",[],"code_block$51339e36-ec41-4317-9bd1-a2bccc6a7e3a",{"variation":441,"version":442,"items":671,"primary":672,"id":677,"slice_type":480,"slice_label":13},[],{"body":673},[674],{"type":425,"text":675,"spans":676},"The private key looks like this:",[],"rich_text$b356d394-a6e7-410f-a2c6-92daa625fccd",{"variation":441,"version":442,"items":679,"primary":680,"id":685,"slice_type":592,"slice_label":13},[],{"language_label":13,"code":681},[682],{"type":588,"text":683,"spans":684},"$ cat private.key\n-----BEGIN ENCRYPTED PRIVATE KEY-----\nMIIJnzBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQI\u002FSQlNhidF\u002FECAggA\nMB0GCWCGSAFlAwQBKgQQ\u002FKqcoZLt2nrZYniObOZRFgSCCVA6GDSvQpmzr7sg40GU\n...\nvAPV8WR\u002FFIzEHL4hzfgFq1PHXy\u002F1dTwgpJRW3Idfigcv9PNC4s\u002FO980DztdUXEnp\nk1v\u002F0kZuvPGMLRpRUhhNlOOfSw==\n-----END ENCRYPTED PRIVATE KEY-----",[],"code_block$9fd808eb-e9e8-44cc-84ba-0088c33c7ecd",{"variation":441,"version":442,"items":687,"primary":688,"id":693,"slice_type":480,"slice_label":13},[],{"body":689},[690],{"type":425,"text":691,"spans":692},"Now that we've successfully generated a certificate and private key, we can inspect these files as follows:",[],"rich_text$f46cf548-7c7d-4142-a515-3a2d704ca8a7",{"variation":441,"version":442,"items":695,"primary":696,"id":701,"slice_type":592,"slice_label":13},[],{"language_label":13,"code":697},[698],{"type":588,"text":699,"spans":700},"$ openssl x509 -in certificate.pem -text\nCertificate:\n    Data:\n        Version: 1 (0x0)\n        Serial Number: 11060314777190734720 (0x997e21b096751b80)\n    Signature Algorithm: sha256WithRSAEncryption\n        Issuer: C=UK, L=London, O=Form3, CN=localhost\n        Validity\n            Not Before: Apr 27 15:55:58 2022 GMT\n            Not After : May 27 15:55:58 2022 GMT\n        Subject: C=UK, L=London, O=Form3, CN=localhost\n        Subject Public Key Info:\n            Public Key Algorithm: rsaEncryption\n                Public-Key: (4096 bit)\n                Modulus:\n                    00:d1:8a:f1:90:4e:0c:26:35:ce:8a:60:f7:a2:01:\n                    3a:41:6f:b4:1e:4a:9c:1d:f8:80:72:2d:a3:dd:4d:\n...",[],"code_block$e6163a9e-7f27-4010-ad86-90048c73ae64",{"variation":441,"version":442,"items":703,"primary":704,"id":709,"slice_type":480,"slice_label":13},[],{"body":705},[706],{"type":425,"text":707,"spans":708},"Here you can see the issuer, validity, and algorithm of the public key. Similarly, the private key can be inspected with:",[],"rich_text$ef15abe9-ad07-4e17-8302-fe34bffff62f",{"variation":441,"version":442,"items":711,"primary":712,"id":717,"slice_type":592,"slice_label":13},[],{"language_label":13,"code":713},[714],{"type":588,"text":715,"spans":716},"$ openssl rsa -in private.key -text\nEnter pass phrase for key.pem:\nPrivate-Key: (4096 bit)\nmodulus:\n    00:ef:f1:21:a1:cb:7e:ee:c9:3d:4c:44:d7:87:10:\n    dc:a1:2e:9d:1f:f4:9a:86:d5:1a:4a:5f:43:0b:7a:\n...",[],"code_block$374b0418-edba-4d64-b298-c872eda9a7cf",{"variation":441,"version":442,"items":719,"primary":720,"id":725,"slice_type":480,"slice_label":13},[],{"body":721},[722],{"type":425,"text":723,"spans":724},"Checking the private key yields less useful information (for an operator, at least), but you can also check the consistency of the key using:",[],"rich_text$558d8daa-d53d-470b-8dcf-af4a07ec1623",{"variation":441,"version":442,"items":727,"primary":728,"id":733,"slice_type":592,"slice_label":13},[],{"language_label":13,"code":729},[730],{"type":588,"text":731,"spans":732},"$ openssl rsa -in private.key -check",[],"code_block$c1ea6286-6598-4d9b-b1ff-0a9b07f1df1c",{"variation":441,"version":442,"items":735,"primary":736,"id":759,"slice_type":480,"slice_label":13},[],{"body":737},[738,741,747,750,756],{"type":447,"text":739,"spans":740},"Certificate chains",[],{"type":425,"text":742,"spans":743},"In order to verify the authenticity of certificates, it's necessary to inspect the issuer (or certificate authority) of a certificate. In the example above, the distinguished name of the issuer is C=UK, L=London, O=Form3, CN=localhost. This distinguished name identifies the certificate authority, who must be trusted in order for the authenticity of a certificate to be verified.",[744],{"start":745,"end":746,"type":456},197,234,{"type":425,"text":748,"spans":749},"The certificate authority has a root certificate, which is used to generate a signature for each certificate that it issues. Combining the signature of a certificate with the public key of the issuer's root certificate allows a signature to be verified. Sometimes this is as simple as combining the signature\u002Fkey of an issued certificate and a root certificate, and sometimes there are intermediate certificates between the issued certificate you're verifying and the ultimate root certificate. Intermediate certificates are typically also issued by the certificate authority, but with a shorter expiry time. This makes them less vulnerable to compromise, and easy to rotate and revoke.",[],{"type":425,"text":751,"spans":752},"On a Linux operating system, a list of root certificates can be found in \u002Fetc\u002Fssl\u002Fcerts. Each certificate authority is represented by its own root certificate, which can be inspected in the same way we inspected the certificate we generated earlier.",[753],{"start":754,"end":755,"type":456},73,87,{"type":425,"text":757,"spans":758},"For example, inspecting the GoDaddy root certificate looks something like this:",[],"rich_text$7601e06a-593a-4f1b-aff3-7c1200dfa104",{"variation":441,"version":442,"items":761,"primary":762,"id":767,"slice_type":592,"slice_label":13},[],{"language_label":13,"code":763},[764],{"type":588,"text":765,"spans":766},"$ openssl x509 -in \u002Fetc\u002Fssl\u002Fcerts\u002FGo_Daddy_Root_Certificate_Authority_-_G2.pem -text\nCertificate:\n    Data:\n        Version: 3 (0x2)\n        Serial Number: 0 (0x0)\n        Signature Algorithm: sha256WithRSAEncryption\n        Issuer: C = US, ST = Arizona, L = Scottsdale, O = \"GoDaddy.com, Inc.\", CN = Go Daddy Root Certificate Authority - G2\n        Validity\n            Not Before: Sep  1 00:00:00 2009 GMT\n            Not After : Dec 31 23:59:59 2037 GMT\n        Subject: C = US, ST = Arizona, L = Scottsdale, O = \"GoDaddy.com, Inc.\", CN = Go Daddy Root Certificate Authority - G2\n        Subject Public Key Info:\n            Public Key Algorithm: rsaEncryption\n                RSA Public-Key: (2048 bit)\n                Modulus:\n                    00:bf:71:62:08:f1:fa:59:34:f7:1b:c9:18:a3:f7:\n                    80:49:58:e9:22:83:13:a6:c5:20:43:01:3b:84:f1:\n                    e6:85:49:9f:27:ea:f6:84:1b:4e:a0:b4:db:70:98:\n...",[],"code_block$3d08c7bc-5a08-4603-9789-2dc32744f613",{"variation":441,"version":442,"items":769,"primary":770,"id":775,"slice_type":480,"slice_label":13},[],{"body":771},[772],{"type":425,"text":773,"spans":774},"We can tell this is a root certificate, because the certificate was used to sign itself. We can verify this self-signed signature as follows:",[],"rich_text$39602d0e-1099-4ba8-9c05-efbef3b2c479",{"variation":441,"version":442,"items":777,"primary":778,"id":783,"slice_type":592,"slice_label":13},[],{"language_label":13,"code":779},[780],{"type":588,"text":781,"spans":782},"$ openssl verify -CAFile \u002Fetc\u002Fssl\u002Fcerts\u002FGo_Daddy_Root_Certificate_Authority_-_G2.pem \u002Fetc\u002Fssl\u002Fcerts\u002FGo_Daddy_Root_Certificate_Authority_-_G2.pem\n\u002Fetc\u002Fssl\u002Fcerts\u002FGo_Daddy_Root_Certificate_Authority_-_G2.pem: OK",[],"code_block$b3b5724a-4cef-4e62-9338-47390c7262f5",{"variation":441,"version":442,"items":785,"primary":786,"id":791,"slice_type":480,"slice_label":13},[],{"body":787},[788],{"type":425,"text":789,"spans":790},"Similarly, if we try to verify the issuer signature for the certificate we generated, we get a verification error:",[],"rich_text$9d691099-5681-48c9-b5e2-23733b79861f",{"variation":441,"version":442,"items":793,"primary":794,"id":799,"slice_type":592,"slice_label":13},[],{"language_label":13,"code":795},[796],{"type":588,"text":797,"spans":798},"$ openssl verify -CAfile \u002Fetc\u002Fssl\u002Fcerts\u002FGo_Daddy_Root_Certificate_Authority_-_G2.pem certificate.pem\nC = UK, L = London, O = Form3\nerror 18 at 0 depth lookup: self signed certificate\nerror certificate.pem: verification failed",[],"code_block$1fe246ec-e005-4ef4-adac-df2a40fa2059",{"variation":441,"version":442,"items":801,"primary":802,"id":825,"slice_type":480,"slice_label":13},[],{"body":803},[804,807,810,813],{"type":425,"text":805,"spans":806},"This error message indicates that the certificate we generated was \"self-signed\". The GoDaddy root certificate is also self-signed, however this is characteristic of a root certificate. The root certificate is trusted, because it was installed by the operating system. Our certificate is less trustworthy, because we just generated it on the fly.",[],{"type":425,"text":808,"spans":809},"TLS certificates in use on the Internet are signed by one of the root certificates installed on your computer, which allows their authenticity to be verified.",[],{"type":425,"text":811,"spans":812},"This can be demonstrated by inspecting a certificate of a website protected by TLS, and then verifying it with its root\u002Fissuing certificate.",[],{"type":425,"text":814,"spans":815},"The TLS certificate of a website can be inspected by using openssl s_client, which normally expects input from stdin (hence the echo -n |):",[816,819,822],{"start":817,"end":818,"type":456},59,75,{"start":820,"end":821,"type":456},111,116,{"start":823,"end":824,"type":456},127,137,"rich_text$0f70de42-6c89-488d-b6ec-797914038efa",{"variation":441,"version":442,"items":827,"primary":828,"id":833,"slice_type":592,"slice_label":13},[],{"language_label":13,"code":829},[830],{"type":588,"text":831,"spans":832},"$ echo -n | openssl s_client -connect www.google.com:443\nCONNECTED(00000004)\ndepth=2 C = US, O = Google Trust Services LLC, CN = GTS Root R1\nverify return:1\ndepth=1 C = US, O = Google Trust Services LLC, CN = GTS CA 1C3\nverify return:1\ndepth=0 CN = www.google.com\nverify return:1\n---\nCertificate chain\n 0 s:CN = www.google.com\n   i:C = US, O = Google Trust Services LLC, CN = GTS CA 1C3\n 1 s:C = US, O = Google Trust Services LLC, CN = GTS CA 1C3\n   i:C = US, O = Google Trust Services LLC, CN = GTS Root R1\n 2 s:C = US, O = Google Trust Services LLC, CN = GTS Root R1\n   i:C = BE, O = GlobalSign nv-sa, OU = Root CA, CN = GlobalSign Root CA\n---\nServer certificate\n-----BEGIN CERTIFICATE-----\nMIIEiTCCA3GgAwIBAgIRALC2MC4uIPl4CoGx9rjcnsMwDQYJKoZIhvcNAQELBQAw\nRjELMAkGA1UEBhMCVVMxIjAgBgNVBAoTGUdvb2dsZSBUcnVzdCBTZXJ2aWNlcyBM \n...\n vkJEyzGxWYiIzgWHYQ==\n-----END CERTIFICATE-----\nsubject=CN = www.google.com\n\nissuer=C = US, O = Google Trust Services LLC, CN = GTS CA 1C3\n\n---\nNo client certificate CA names sent\nPeer signing digest: SHA256\nPeer signature type: ECDSA\nServer Temp Key: X25519, 253 bits\n---\nSSL handshake has read 4297 bytes and written 386 bytes\nVerification: OK\n---\nNew, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384\nServer public key is 256 bit\nSecure Renegotiation IS NOT supported\nCompression: NONE\nExpansion: NONE\nNo ALPN negotiated\nEarly data was not sent\nVerify return code: 0 (ok)\n---\nDONE",[],"code_block$4c17c52d-c080-4773-8ef7-4b565d4ddd11",{"variation":441,"version":442,"items":835,"primary":836,"id":847,"slice_type":480,"slice_label":13},[],{"body":837},[838,844],{"type":425,"text":839,"spans":840},"Note that the Common Name of this certificate was google.com, indicating that this certificate can only be used to encrypt traffic to this domain name. Even if the certificate is verified as authentic, it cannot be used to serve TLS traffic from any other domain in a trusted capacity.",[841],{"start":842,"end":843,"type":456},50,60,{"type":425,"text":845,"spans":846},"A certificate file can be generated for verification with:",[],"rich_text$75b0ad57-4efd-47c1-a46d-0ca9bb6d77b6",{"variation":441,"version":442,"items":849,"primary":850,"id":855,"slice_type":592,"slice_label":13},[],{"language_label":13,"code":851},[852],{"type":588,"text":853,"spans":854},"$ echo -n | openssl s_client -connect www.google.com:443 | openssl x509 > google.pem",[],"code_block$8cbd3b58-4004-4a0a-b31c-865e3190a2ef",{"variation":441,"version":442,"items":857,"primary":858,"id":875,"slice_type":480,"slice_label":13},[],{"body":859},[860,869],{"type":425,"text":861,"spans":862},"If you inspect this certificate (openssl x509 -in google.pem -text), you will see that this certificate was issued by \"Google Trust Services\". A quick search of your root certificate directory (cat \u002Fetc\u002Fssl\u002Fcerts | grep google) will show that Google Trust Services is not a root certificate authority. This means that there is a chain of issuing certificates between the one in use at google.com and the certificate authority that signed the first certificate in the chain.",[863,866],{"start":864,"end":865,"type":456},33,66,{"start":867,"end":868,"type":456},194,226,{"type":425,"text":870,"spans":871},"We can download the certificate chain separately using openssl as follows:",[872],{"start":873,"end":874,"type":456},55,62,"rich_text$d87e61fe-0927-4254-b295-a49bcf933c4c",{"variation":441,"version":442,"items":877,"primary":878,"id":883,"slice_type":592,"slice_label":13},[],{"language_label":13,"code":879},[880],{"type":588,"text":881,"spans":882},"$ echo -n | openssl s_client -connect www.google.com:443 -showcerts > google-chain.pem",[],"code_block$ff45fef7-1e7e-416c-b3aa-12e0b2fd0751",{"variation":441,"version":442,"items":885,"primary":886,"id":891,"slice_type":480,"slice_label":13},[],{"body":887},[888],{"type":425,"text":889,"spans":890},"The original certificate can then be manually verified against its root certificate via the certificate chain with:",[],"rich_text$6bf94bf2-78d8-42b1-b65c-a7f890f88beb",{"variation":441,"version":442,"items":893,"primary":894,"id":899,"slice_type":592,"slice_label":13},[],{"language_label":13,"code":895},[896],{"type":588,"text":897,"spans":898},"$ openssl verify -CAfile google-chain.pem google.pem\ngoogle.pem: OK",[],"code_block$1424d266-83c6-4340-a9f0-74902d8c7819",{"variation":441,"version":442,"items":901,"primary":902,"id":907,"slice_type":480,"slice_label":13},[],{"body":903},[904],{"type":425,"text":905,"spans":906},"The verification of Google's certificate against the root certificate installed in your operating system demonstrates the difference in trust between the public certificates in use on the Internet for TLS, and the self-signed certificates you might generate locally. The fact that the certificates in use online can be verified against known certificates on your computer demonstrates that they have been issued to a trustworthy server.",[],"rich_text$5d07d717-304b-40c7-b578-919bae23c0a1",{"variation":441,"version":442,"items":909,"primary":910,"id":921,"slice_type":480,"slice_label":13},[],{"body":911},[912,915],{"type":447,"text":913,"spans":914},"TLS vs. SSH certificates",[],{"type":425,"text":916,"spans":917},"According to man ssh-keygen, the certificates used for SSH are a different, and much more simple, format than X.509 certificates used for TLS. SSH certificates are used in a similar way to the X.509 certificates used in TLS: they consist of public and private keys, but the format is different to the certificates described in this post.",[918],{"start":919,"end":920,"type":456},13,27,"rich_text$3e073ed7-c4a8-4240-b93f-7d3d23b8396f",{"variation":441,"version":442,"items":923,"primary":924,"id":938,"slice_type":480,"slice_label":13},[],{"body":925},[926,929,935],{"type":447,"text":927,"spans":928},"Example: TLS for HTTPS web servers",[],{"type":425,"text":930,"spans":931},"When you connect to a server that offers TLS, the server will be configured to send you its public certificate and will encrypt data with its private key. I'm not going to delve into the details of how TLS works here, but instead demonstrate how you might configure a simple web server with the materials it needs to make TLS possible. I'll be using nginx running in a Docker container to provide a small example.",[932],{"start":933,"end":934,"type":456},350,355,{"type":425,"text":936,"spans":937},"First of all, we'll need some static content to serve as our web page:",[],"rich_text$10d9c365-2391-4a42-84d1-7ecc3fcfecd1",{"variation":441,"version":442,"items":940,"primary":941,"id":946,"slice_type":592,"slice_label":13},[],{"language_label":13,"code":942},[943],{"type":588,"text":944,"spans":945},"$ cat \u003C\u003C EOF > index.html\nHello world!\n\nThis web page is protected using TLS!\nEOF",[],"code_block$1a77248f-6e8a-463a-8806-71e8b08ae1d5",{"variation":441,"version":442,"items":948,"primary":949,"id":956,"slice_type":480,"slice_label":13},[],{"body":950},[951],{"type":425,"text":952,"spans":953},"Next, we'll need to configure an nginx server to serve this web page:",[954],{"start":864,"end":955,"type":456},38,"rich_text$d8bcb2ac-7f46-47ca-9485-700fa3980761",{"variation":441,"version":442,"items":958,"primary":959,"id":964,"slice_type":592,"slice_label":13},[],{"language_label":13,"code":960},[961],{"type":588,"text":962,"spans":963},"$ cat \u003C\u003C EOF > nginx.conf\nevents {}\nhttp {\n    server {\n        root \u002Fwww\u002F;\n        location \u002F {}\n    }\n}\nEOF",[],"code_block$f5385629-999f-4323-89c5-eab29a2a6b18",{"variation":441,"version":442,"items":966,"primary":967,"id":975,"slice_type":480,"slice_label":13},[],{"body":968},[969],{"type":425,"text":970,"spans":971},"Then, we can package nginx with our web page and config as follows:",[972],{"start":973,"end":974,"type":456},21,26,"rich_text$653218c4-3109-43e7-bca1-9fa8f1ca0b69",{"variation":441,"version":442,"items":977,"primary":978,"id":983,"slice_type":592,"slice_label":13},[],{"language_label":13,"code":979},[980],{"type":588,"text":981,"spans":982},"$ cat \u003C\u003C EOF > Dockerfile\nFROM nginx\nCOPY index.html \u002Fwww\u002Findex.html\nCOPY nginx.conf \u002Fetc\u002Fnginx\u002Fnginx.conf\nEOF",[],"code_block$41f183ba-86ed-43ec-9bb3-e809ff92ad94",{"variation":441,"version":442,"items":985,"primary":986,"id":991,"slice_type":480,"slice_label":13},[],{"body":987},[988],{"type":425,"text":989,"spans":990},"Now, we can build and run this image with:",[],"rich_text$bf97c58d-2282-45f7-9c68-7ef6c006539a",{"variation":441,"version":442,"items":993,"primary":994,"id":999,"slice_type":592,"slice_label":13},[],{"language_label":13,"code":995},[996],{"type":588,"text":997,"spans":998},"$ docker build -t nginx-tls .\n$ docker run -p 8080:80 nginx-tls",[],"code_block$c0b20039-8a8e-4274-b516-8463e638f488",{"variation":441,"version":442,"items":1001,"primary":1002,"id":1007,"slice_type":480,"slice_label":13},[],{"body":1003},[1004],{"type":425,"text":1005,"spans":1006},"OK, now we can test our server by making a web request:",[],"rich_text$a7a591e1-23ab-4de4-bc5a-2cff2a213c8a",{"variation":441,"version":442,"items":1009,"primary":1010,"id":1015,"slice_type":592,"slice_label":13},[],{"language_label":13,"code":1011},[1012],{"type":588,"text":1013,"spans":1014},"$ curl localhost:8080\u002F\nHello world!\n\nThis web page is protected using TLS!",[],"code_block$fd928293-97b8-4f32-b0aa-d2bec80f6dff",{"variation":441,"version":442,"items":1017,"primary":1018,"id":1026,"slice_type":480,"slice_label":13},[],{"body":1019},[1020],{"type":425,"text":1021,"spans":1022},"Now that we've got a functioning web server, we can try to add TLS to it. The first thing to do is to update the nginx configuration with TLS details:",[1023],{"start":1024,"end":1025,"type":456},113,118,"rich_text$aa4849bd-20d0-488f-adfa-4fb9acd63064",{"variation":441,"version":442,"items":1028,"primary":1029,"id":1034,"slice_type":592,"slice_label":13},[],{"language_label":13,"code":1030},[1031],{"type":588,"text":1032,"spans":1033},"$ cat \u003C\u003C EOF > nginx.conf\nevents {}\nhttp {\n    server {\n        root \u002Fwww\u002F;\n        location \u002F {}\n\n        listen 443 ssl;\n        ssl_certificate certificate.pem;\n        ssl_certificate_key private.key;\n    }\n}\nEOF",[],"code_block$38cdd91f-20b8-48ad-bf97-a56bbc0a8d8c",{"variation":441,"version":442,"items":1036,"primary":1037,"id":1042,"slice_type":480,"slice_label":13},[],{"body":1038},[1039],{"type":425,"text":1021,"spans":1040},[1041],{"start":1024,"end":1025,"type":456},"rich_text$af934ad8-f608-4ac1-8b9c-c938a0ad008c",{"variation":441,"version":442,"items":1044,"primary":1045,"id":1049,"slice_type":592,"slice_label":13},[],{"language_label":13,"code":1046},[1047],{"type":588,"text":1032,"spans":1048},[],"code_block$2a12fe5b-9f20-43e0-82d4-a3dce67408d9",{"variation":441,"version":442,"items":1051,"primary":1052,"id":1060,"slice_type":480,"slice_label":13},[],{"body":1053},[1054],{"type":425,"text":1055,"spans":1056},"This configuration uses the certificates we generated earlier. To re-cap, we generated these files using openssl:",[1057],{"start":1058,"end":1059,"type":456},105,112,"rich_text$77937f64-6fe0-4ebc-98a1-38248e55144e",{"variation":441,"version":442,"items":1062,"primary":1063,"id":1067,"slice_type":592,"slice_label":13},[],{"language_label":13,"code":1064},[1065],{"type":588,"text":612,"spans":1066},[],"code_block$82a8fbe7-2a1b-42f6-a3e1-b43d55f7b20c",{"variation":441,"version":442,"items":1069,"primary":1070,"id":1075,"slice_type":480,"slice_label":13},[],{"body":1071},[1072],{"type":425,"text":1073,"spans":1074},"The certificate files will also need to be present in the Dockerfile:",[],"rich_text$24d7b7a6-57b5-4b2a-8c03-d5d49a0a5a3d",{"variation":441,"version":442,"items":1077,"primary":1078,"id":1083,"slice_type":592,"slice_label":13},[],{"language_label":13,"code":1079},[1080],{"type":588,"text":1081,"spans":1082},"$ cat \u003C\u003C EOF > Dockerfile\nFROM nginx\nCOPY index.html \u002Fwww\u002Findex.html\nCOPY nginx.conf \u002Fetc\u002Fnginx\u002Fnginx.conf\nCOPY *.pem \u002Fetc\u002Fnginx\u002F\nCOPY *.key \u002Fetc\u002Fnginx\u002F\nEOF",[],"code_block$44e9c84d-15c5-4a29-a9ba-31e40cf57ca4",{"variation":441,"version":442,"items":1085,"primary":1086,"id":1091,"slice_type":480,"slice_label":13},[],{"body":1087},[1088],{"type":425,"text":1089,"spans":1090},"We can then build and run the container in a similar way to before:",[],"rich_text$b7b7fce5-d5dd-473f-bd17-3083d1b99ead",{"variation":441,"version":442,"items":1093,"primary":1094,"id":1099,"slice_type":592,"slice_label":13},[],{"language_label":13,"code":1095},[1096],{"type":588,"text":1097,"spans":1098},"$ docker build -t nginx-tls --no-cache .\n$ docker run -p 8080:443 nginx-tls",[],"code_block$ddd52867-df4a-4b6a-a7da-0abe6fbbb64a",{"variation":441,"version":442,"items":1101,"primary":1102,"id":1107,"slice_type":480,"slice_label":13},[],{"body":1103},[1104],{"type":425,"text":1105,"spans":1106},"Now, if we try to get the webpage via HTTP, it fails:",[],"rich_text$9e72017f-0b1f-431c-b317-a15886a83355",{"variation":441,"version":442,"items":1109,"primary":1110,"id":1115,"slice_type":592,"slice_label":13},[],{"language_label":13,"code":1111},[1112],{"type":588,"text":1113,"spans":1114},"$ curl localhost:8080\n\u003Chtml>\n\u003Chead>\u003Ctitle>400 The plain HTTP request was sent to HTTPS port\u003C\u002Ftitle>\u003C\u002Fhead>\n\u003Cbody>\n\u003Ccenter>\u003Ch1>400 Bad Request\u003C\u002Fh1>\u003C\u002Fcenter>\n\u003Ccenter>The plain HTTP request was sent to HTTPS port\u003C\u002Fcenter>\n\u003Chr>\u003Ccenter>nginx\u002F1.21.6\u003C\u002Fcenter>\n\u003C\u002Fbody>\n\u003C\u002Fhtml>",[],"code_block$63b4af79-842e-41d6-b80c-8b179af42009",{"variation":441,"version":442,"items":1117,"primary":1118,"id":1123,"slice_type":480,"slice_label":13},[],{"body":1119},[1120],{"type":425,"text":1121,"spans":1122},"And, if we try to get the webpage via HTTPS, it also fails:",[],"rich_text$0feafa2a-38b8-4608-8d05-d668f3cd049e",{"variation":441,"version":442,"items":1125,"primary":1126,"id":1131,"slice_type":592,"slice_label":13},[],{"language_label":13,"code":1127},[1128],{"type":588,"text":1129,"spans":1130},"$ curl https:\u002F\u002Flocalhost:8080\ncurl: (60) SSL certificate problem: self signed certificate\nMore details here: https:\u002F\u002Fcurl.haxx.se\u002Fdocs\u002Fsslcerts.html\n\ncurl failed to verify the legitimacy of the server and therefore could not\nestablish a secure connection to it. To learn more about this situation and\nhow to fix it, please visit the web page mentioned above.",[],"code_block$349328f0-67f5-4231-b7e2-c21ffd34c733",{"variation":441,"version":442,"items":1133,"primary":1134,"id":1147,"slice_type":480,"slice_label":13},[],{"body":1135},[1136],{"type":425,"text":1137,"spans":1138},"This is because we're using a self-signed certificate. Web browsers, curl, and most HTTP clients will fail if you try to make requests over TLS and the server presents a self-signed certificate. In this case, there's no way to know if you can trust the server or not. However, if we try again and tell curl to ignore self-signed certificates (-k), we are successful:",[1139,1141,1144],{"start":1140,"end":754,"type":456},69,{"start":1142,"end":1143,"type":456},302,306,{"start":1145,"end":1146,"type":456},343,345,"rich_text$ba55391a-1b4f-499e-bfb5-7465b225f318",{"variation":441,"version":442,"items":1149,"primary":1150,"id":1155,"slice_type":592,"slice_label":13},[],{"language_label":13,"code":1151},[1152],{"type":588,"text":1153,"spans":1154},"$ curl https:\u002F\u002Flocalhost:8080 -k\nHello world!\n\nThis web page is protected using TLS!",[],"code_block$a9260829-3db2-4386-bae5-4b6767474ba9",{"variation":441,"version":442,"items":1157,"primary":1158,"id":1166,"slice_type":480,"slice_label":13},[],{"body":1159},[1160],{"type":425,"text":1161,"spans":1162},"If you were working with self-signed certificates regularly, or with a private certificate authority whose root certificates aren't installed automatically, it is possible to import custom root certificates into your system's list of trusted certificates. Doing so would mean that clients like curl would recognise the authenticity of your certificate, rather than failing to verify its signature.",[1163],{"start":1164,"end":1165,"type":456},294,298,"rich_text$7e28ade1-9719-40ed-9775-aad2f4de7193",{"variation":441,"version":442,"items":1168,"primary":1169,"id":1189,"slice_type":480,"slice_label":13},[],{"body":1170},[1171,1174,1186],{"type":447,"text":1172,"spans":1173},"Summary",[],{"type":425,"text":1175,"spans":1176},"So there you have it! Most TLS certificates are X.509 certificates, and whether you see them in *.pem, *.crt, or *.key files they're all likely to be in the same format. Certificates can be generated, inspected, and verified using the openssl command, and this applies to both self-signed certificates you might generate for testing, as well as certificates signed by a trusted certificate authority. Using X.509 certificates for TLS on web servers is relatively straightforward, and easy to configure in server applications like nginx.",[1177,1178,1181,1183],{"start":541,"end":543,"type":456},{"start":1179,"end":1180,"type":456},102,108,{"start":1024,"end":1182,"type":456},119,{"start":1184,"end":1185,"type":456},530,535,{"type":425,"text":1187,"spans":1188},"I hope you've found this post useful, and walk away from it slightly less confounded than I was when I started writing it!",[],"rich_text$3e1cb051-fba6-4447-8598-f6151f31c73d",1788466508471]