{"id":19929083,"url":"https://github.com/thescriptguy/getcertificatechain","last_synced_at":"2025-06-14T20:38:56.828Z","repository":{"id":156750997,"uuid":"613129961","full_name":"TheScriptGuy/getCertificateChain","owner":"TheScriptGuy","description":"Retrieve the certificate chain from a hostname.","archived":false,"fork":false,"pushed_at":"2024-04-24T14:55:37.000Z","size":103,"stargazers_count":8,"open_issues_count":1,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-05-03T10:43:37.347Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/TheScriptGuy.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-03-13T00:13:44.000Z","updated_at":"2024-09-01T12:03:32.000Z","dependencies_parsed_at":"2023-11-06T03:28:14.877Z","dependency_job_id":"220fc017-7763-4833-a36c-dd6fa7c1bb04","html_url":"https://github.com/TheScriptGuy/getCertificateChain","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/TheScriptGuy/getCertificateChain","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheScriptGuy%2FgetCertificateChain","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheScriptGuy%2FgetCertificateChain/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheScriptGuy%2FgetCertificateChain/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheScriptGuy%2FgetCertificateChain/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/TheScriptGuy","download_url":"https://codeload.github.com/TheScriptGuy/getCertificateChain/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheScriptGuy%2FgetCertificateChain/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259880683,"owners_count":22925986,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-12T22:41:50.413Z","updated_at":"2025-06-14T20:38:56.811Z","avatar_url":"https://github.com/TheScriptGuy.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# :closed_lock_with_key::closed_lock_with_key::closed_lock_with_key: Get the Certificate Chain :closed_lock_with_key::closed_lock_with_key::closed_lock_with_key:\n\nGetting the certificate chain for a hostname should not be difficult!\n\nSometimes websites do not present the full chain (against RFC recommendations) which means it's hard to find the certificate chain and troubleshoot.\n\nThis script will attempt to use the breadcrumbs that are left by the certificate to build the chain and output it into files.\n\nIt's worked on publicly available websites (at least the ones I've tested). Happy to troubleshoot if an error pops up.\n\n\n# Requirements\n```bash\n$ python3 -m pip install re cryptography argparse ssl\n```\n\n# :runner: How to run\nTo get the arguments available `python3 getCertChain.py --help`. Should present information like this:\n```bash\n$ python3 getCertChain.py -h\nusage: getCertChain.py [-h] [--hostname HOSTNAME] [--removeCertificateFiles] [--getCAcertPEM] [--insecure]\n\nGet Certificate Chain v0.07\n\noptional arguments:\n  -h, --help            show this help message and exit\n  --hostname HOSTNAME   The hostname:port pair that the script should connect to. Defaults to www.google.com:443.\n  --removeCertificateFiles\n                        Remove the certificate files in current working directory (*.crt, *.pem).\n  --getCAcertPEM        Get cacert.pem from curl.se website to help find Root CA.\n  --insecure            Allow insecure connections to establish.\n```\n\n# :books: Examples\nTo get the certificate chain for www.google.com\n```bash\n$ python3 getCertChain --hostname www.google.com\n$\n```\nIt by default will not display any output (unless it struggles to find the Root CA).\n\nTo see the files it created (from where the script ran):\n```bash\n$ ls -l\ntotal 28\n-rw-r--r-- 1 gituser gituser  1911 Mar 12 16:38 0-gts-root-r1.crt\n-rw-r--r-- 1 gituser gituser  1996 Mar 12 16:38 1-gts-ca-1c3.crt\n-rw-r--r-- 1 gituser gituser  1631 Mar 12 16:38 2-www.google.com.crt\n-rw-r--r-- 1 gituser gituser 13385 Mar 12 16:36 getCertChain.py\n```\nIf you notice the prefix of each new file that was created (i.e. 0-, 1-, 2-) this is the order of the chain with \n* `0-` being the Root CA\n* `1-` being the intermediate CA\n* `2-` being the endpoint/website certificate\n\nThe rest of the file name is deduced from the commonName in the certificate.\n\nOn some occasions, the intermediate CA does not present an Authority Information Access field (AIA) with a URI on where to get the file from. \n\nTo help build the chain, we need some `external` help - leveraging the `cacert.pem` file from `curl.se` website.\nThis is the url: :link: `https://curl.se/ca/cacert.pem`\n\nTo get the `cacert.pem` file as part of the connection from `--hostname` argument:\n```bash\n$ python3 getCertChain.py --hostname www.google.com --getCAcertPEM\n```\n\nYou could also run it by itself:\n```bash\n$ python3 getCertChain.py --getCAcertPEM\n```\n\n# :dash::hole: Clean up all the files\n```bash\n$ python3 getCertChain.py --removeCertificateFiles\nRemoving file 1-gts-ca-1c3.crt\nRemoving file 2-www.google.com.crt\nRemoving file 0-gts-root-r1.crt\nRemoving file cacert.pem\n```\n\n# :lock: :bulb: Windows Powershell :bulb: :lock:\nUsing AI, I wrote a powershell script that can help accomplish the same thing within windows. This only downloads the certificates. It does not have the capability to remove them.\nTo download the chain that the hostname presents:\nUsage:\n```powershell\n.\\getCertificateChain.ps1 -hostname www.example.com\n```\nTo download the chain that the hostname presents and use the Authority Information Access (AIA) Fields use the `-useAIA` argument to assist:\n```powershell\n.\\getCertificateChain.ps1 -hostname www.example.com -useAIA\n```\n\n# :warning: MitM proxies/services\nGiven the way MitM proxies and decryption services work, this tool is not intended to be used behind devices that perform SSL/TLS decryption as those devices strip the `Authority Information Access` (AIA), and alter the `Subject Key Identifier` (SKI) and `Authority Key Identifier` (AKI) fields.\n\n# Known issues 🌩️\nIf a website's certificate chain has 4 or more tiers and one of the intermediate CA's do not have a AIA field - the script will only show the website certificate and the first issuing CA. \n\nSomething like this:\n* Root CA\n  * Issuing CA 1\n    * Issuing Sub CA 1\n      * Website certificate (example.com)\n\nScript will only output `Issuing Sub CA 1` and `website certificate`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthescriptguy%2Fgetcertificatechain","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthescriptguy%2Fgetcertificatechain","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthescriptguy%2Fgetcertificatechain/lists"}