I Built a CSR Parser in Python (That OpenSSL Already Does Better)
You know that feeling when you spend hours building something, polish it up, write comprehensive tests, package it properly… and then discover OpenSSL has been doing the exact same thing with a simple one-liner all along?
Yeah. That happened to me.
The “Problem” I Solved
A colleague reached out with a certificate issue: their webserver TLS certificate was missing Subject Alternative Names (SANs). They suspected the Certificate Authority was stripping them out during issuance.
I did a quick test—created a CSR with SANs in PowerShell, submitted it to the CA, and got back a perfectly valid certificate with all the SANs intact. So the CA wasn’t the problem. That meant we needed to look at their original CSR to see if the SANs were actually in the request.
“Can you send me the .ini file you used to generate the CSR?” I asked. For reasons that aren’t worth getting into, that file wasn’t available. All they had was the CSR itself—a base64-encoded blob that looked like this:
-----BEGIN CERTIFICATE REQUEST-----
MIICvDCCAaQCAQAwdzELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWEx
FjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xEzARBgNVBAoMCkV4YW1wbGUgQ28xEDAO
BgNVBAsMB0RldlRlYW0xFDASBgNVBAMMC2V4YW1wbGUuY29tMIIBIjANBgkqhkiG
...
-----END CERTIFICATE REQUEST-----
I threw it into CyberChef, base64 decoded it, and stared at the binary output. Sure, I could pick out some ASCII strings like “California” and “San Francisco,” but the structure? The extensions? The SANs? Completely opaque.
After a surprisingly brief search for a ready-made decoder (in hindsight, not nearly long enough), I thought: “You know what? I deal with CSRs fairly regularly. I should just write a tool to parse these things properly.”
Certificate Signing Requests are base64-encoded blobs that contain important information you need to verify before sending them off to a Certificate Authority:
- What’s the Common Name (CN)?
- What Subject Alternative Names (SANs) are included?
- What’s the public key algorithm and size?
- Is the signature valid?
Being moderately proficient in Python, I thought: “I should write a script for this!”
What I Built
Enter csr-parser: a full-featured Python CLI tool that parses CSRs and displays all their information in a nice, human-readable format (or JSON if you’re into that).
Features include:
- Parse PEM and DER formatted CSRs
- Extract all subject information (CN, O, OU, C, ST, L, etc.)
- Display public key details (algorithm, key size, EC curve names)
- Show signature algorithm information
- Parse all X.509 extensions (SANs, Key Usage, Extended Key Usage, etc.)
- Verify the CSR’s self-signature
- Multiple input methods (file, stdin, or direct string)
- JSON output option for scripting
I used the Python cryptography library, added proper CLI argument parsing, created example files, polished it, and added documentation… the whole nine yards.
Here’s what it looks like in action:
$ csr-parser -f examples/example.csr
======================================================================
Certificate Signing Request (CSR) Information
======================================================================
Subject:
C: US
ST: California
L: San Francisco
O: Example Co
OU: DevTeam
CN: example.com
Public Key:
algorithm: RSAPublicKey
key_size: 2048
Signature Algorithm:
Name: sha256WithRSAEncryption
Hash Algorithm: sha256
OID: 1.2.840.113549.1.1.11
Signature Valid: True
Extensions:
subjectAltName (OID: 2.5.29.17)
Critical: False
Value:
- DNS:example.com
- DNS:www.example.com
======================================================================
Pretty slick, right? I was quite proud of it.
The Plot Twist
Fast forward to today (well, a few days ago—sorry, slow writer here). I was doing some unrelated PKI work and I saw it.
openssl req -in example.csr -noout -text
Openssl has a argument -text that can be used to see the contents of a CSR.
$ openssl req -in examples/example.csr -noout -text
Certificate Request:
Data:
Version: 1 (0x0)
Subject: C = US, ST = California, L = San Francisco, O = Example Co, OU = DevTeam, CN = example.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:c8:6d:...
Exponent: 65537 (0x10001)
Attributes:
Requested Extensions:
X509v3 Subject Alternative Name:
DNS:example.com, DNS:www.example.com
Signature Algorithm: sha256WithRSAEncryption
Signature Value:
7f:3a:...
Oh.
OH NO.
Not only does this work perfectly, but OpenSSL has been shipping with basically every Unix-like system since the dawn of time. No pip install required. No dependencies. No Python version requirements. Just… there. Waiting. Laughing at me.
So Was It Useless?
Here’s where I could spiral into despair about wasted time, but honestly? Building csr-parser was a great learning experience, even if the end result is technically redundant.
What I Actually Learned
1. X.509 and PKI internals
Building this forced me to truly understand certificate structure at a low level. I learned that Subject Alternative Names are stored in extension OID 2.5.29.17, why some extensions are marked critical vs. non-critical, and how ASN.1 encoding actually works (it’s a nested mess of Type-Length-Value structures). When you’re debugging why your parser thinks a UTF8String is an integer, you learn things that simply running an OpenSSL command will never teach you.
2. The Python cryptography library
I got hands-on with a library I’d only used superficially before. Understanding how to work with x509.CertificateSigningRequest objects, navigate extensions programmatically, and handle both PEM and DER formats—these skills transfer to other certificate work, JWT validation, and general cryptographic operations I’ll use in future projects.
3. Modern Python development practices
While I’ve used uv before—and seriously, if you haven’t tried it, go check it out; it’s absurdly fast—this project pushed me to structure things properly with pyproject.toml (something I’m trying to do more consistently) and build a real CLI with argparse that handles multiple input methods gracefully. These patterns are transferable to any Python tool I build.
4. Check the standard toolbox first
The most valuable lesson: before spending hours building something, thoroughly check if the standard Unix tools already do it. Not a quick Google, but actually reading man pages, trying the obvious commands, and asking experienced colleagues. I skipped all of that and paid the price in humility.
When Reinventing the Wheel Actually Makes Sense
That said, there are legitimate reasons my tool might be useful in specific scenarios:
- Scripting with JSON output:
csr-parser -f example.csr --jsongives you structured JSON you can easily parse in scripts, whereas OpenSSL’s text output requires more complex parsing - Programming libraries: If you’re building a larger Python application that needs to parse CSRs, importing my library is cleaner than shelling out to OpenSSL
- Cross-platform consistency: Python and pip (and uv) work the same everywhere; OpenSSL versions and output formats vary across systems
- Learning tool: The code itself is a good reference for understanding how CSRs work
But let’s be real: 99% of the time, the OpenSSL one-liner is what you actually want.
The Silver Lining
The best part about this whole experience? I now have a great story about over-engineering a solution. And you just read it!
Plus, the tool is out there on the various code retirement homes (GitHub and GitLab). Maybe someone will find it useful. Either way, it was fun to build (even though I definitely banged my head against the wall a few times), and most importantly I learned a lot in the process.
So yes, I built a tool that OpenSSL already does better with a simple command. But in the process, I learned about cryptography, improved my Python skills, and got a good story out of it.
Sometimes the journey is more valuable than the destination. Or something like that. I’m going to keep telling myself that anyway.
If you want to check out the code or use it for some reason (though seriously, just use OpenSSL), you can find it at GitHub or GitLab
And remember: before you build that cool tool you’ve been thinking about, maybe Google if it already exists first. I swear I did this. I just didn’t Google hard enough—Google-fu belt demotion incoming. Learn from my mistakes.
P.S. - If you actually do find a legitimate use case for csr-parser over the OpenSSL command, please let me know. My ego could use the validation.