feat: Bring Go and Python implementations to feature parity
test-go.yaml / test-go (push) Successful in 1m27s
test-python.yaml / test-python (push) Successful in 1m36s

Go:
- Read and write simple-ca.json shared with the Python implementation
- Add make-crl and revoke-cert commands and record certificate history
- Rename --aia-base-url to --ca-publish-base-url
- Add CRL Distribution Point extension to issuing CA and leaf
  certificates
- Take days and issuing_ca defaults from simple-ca.json
- Include email SANs in server certificates
- Reject IPv4 SANs with out-of-range octets
- Record existing issuing CAs and rebuild the CA bundle
- Print errors once

Python:
- Add make-cert --type server|user and email SANs
- Reject IPv4 SANs with out-of-range octets
- Skip make-ca when the root CA exists and no issuing CA is given
- Build ca_bundle.pem from issuing CA subdirectories
- Accept a bare filename in make-pfx and drop the root key requirement
- Honour explicit --days values and reject values below 1
- Persist and increment CRL numbers in simple-ca.json

Update README and add tests for the new behaviour.
This commit is contained in:
slawek committed 2026-10-16 14:20:04 +02:00
1 parent 27461a0fbe
commit 9c84e82672
5 files changed
+757 -170

No files matched your search

+29 -13
View File
@@ -9,15 +9,16 @@ Tools for creating and managing a simple Certificate Authority for testing and d
| | `simple-ca.sh` | `simple-ca.py` | Go binary |
|---|---|---|---|
| Usage | sourced function library | CLI | compiled CLI |
| Config file | none | `simple-ca.json` | none |
| AIA base URL | `aia_base_url.txt` | `simple-ca.json` | `aia_base_url.txt` |
| Certificate history | no | yes | no |
| CRL generation | no | yes | no |
| Revocation | no | yes | no |
| Config file | none | `simple-ca.json` | `simple-ca.json` |
| Publish base URL | `aia_base_url.txt` (AIA) | `simple-ca.json` (AIA + CDP) | `simple-ca.json` (AIA + CDP) |
| Server and user certificates | yes | yes | yes |
| Certificate history | no | yes | yes |
| CRL generation | no | yes | yes |
| Revocation | no | yes | yes |
| PFX (`--apple-openssl`) | yes | yes | yes |
| Requires | bash/zsh + openssl | Python 3.8+ + openssl | none (native crypto) |
All variants share the same directory layout and produce interchangeable files.
All variants share the same directory layout and produce interchangeable files. The Python and Go variants share `simple-ca.json`, so a CA directory can be managed by either of them.
## Directory layout
@@ -26,7 +27,7 @@ CA_DIR/
ca_cert.pem root CA certificate
ca_key.pem root CA private key
ca_bundle.pem root + all issuing CA certs concatenated
aia_base_url.txt base URL for AIA extension (shell/Go only)
aia_base_url.txt base URL for AIA extension (shell only)
{name}_cert.pem certificate issued by root CA
{name}_key.pem key for certificate issued by root CA
{issuing_ca}/
@@ -36,7 +37,7 @@ CA_DIR/
{name}_key.pem key for certificate issued by issuing CA
```
Python additionally writes:
Python and Go additionally write:
```
CA_DIR/
@@ -46,6 +47,17 @@ CA_DIR/
crl.pem issuing CA CRL (make-crl)
```
`simple-ca.json` keys:
- `name`, `created` - root CA name and creation time.
- `ca_publish_base_url` - base URL for AIA and CRL Distribution Point extensions.
- `subordinates` - issuing CA directory names.
- `issuing_ca` - default for `--issuing-ca`.
- `days` - defaults for `--days`: `ca`, `cert`, `crl`.
- `openssl` - path to the openssl binary (Python only).
- `history` - issued certificates per CA (`ca` for the root CA): `name`, `serial`, `created`, `expires`, `revoked`.
- `crl_number` - last CRL number issued per CA.
Use `ca_bundle.pem` with `openssl verify -CAfile CA_DIR/ca_bundle.pem` — this works identically on Linux, macOS, and Windows without relying on hash symlinks.
---
@@ -109,7 +121,7 @@ python3 simple-ca.py COMMAND [OPTIONS] [ARGS]
```bash
make-ca [--ca-dir DIR] [--days N] [--ca-publish-base-url URL] [--issuing-ca NAME] CA_NAME
make-cert [--ca-dir DIR] [--cert-dir DIR] [--days N] [--issuing-ca NAME] SUBJECT [SAN ...]
make-cert [--ca-dir DIR] [--cert-dir DIR] [--days N] [--issuing-ca NAME] [--type server|user] SUBJECT [SAN ...]
make-pfx [--ca-dir DIR] [--issuing-ca NAME] [--password PASS] [--apple-openssl] CERT_PATH
make-crl [--ca-dir DIR] [--issuing-ca NAME] [--days N]
revoke-cert [--ca-dir DIR] [--issuing-ca NAME] CERT_PATH
@@ -117,6 +129,8 @@ revoke-cert [--ca-dir DIR] [--issuing-ca NAME] CERT_PATH
`--ca-publish-base-url` embeds both AIA (Authority Information Access) and CRL Distribution Point extensions in issued certificates, pointing to the published location of the CA cert and CRL file.
`--type server` (default) creates a TLS certificate (serverAuth + clientAuth) with `SUBJECT` as the CN and first SAN, which must be a DNS name. `--type user` creates a certificate with clientAuth, emailProtection and codeSigning, where `SUBJECT` is any CN. SANs can be DNS names, IPv4 addresses or email addresses.
### Example — two-level CA with CRL
```bash
@@ -134,7 +148,7 @@ python3 simple-ca.py make-crl --ca-dir /tmp/ca --issuing-ca servers
## Go binary
Equivalent to the shell variant in features. Uses native Go crypto — no `openssl` subprocess required except for `--apple-openssl` PFX generation.
Equivalent to the Python variant in features and shares its `simple-ca.json`. Uses native Go crypto — no `openssl` subprocess required except for `--apple-openssl` PFX generation.
```bash
cd src/simple-ca && go build -o simple-ca .
@@ -143,9 +157,11 @@ cd src/simple-ca && go build -o simple-ca .
### Commands
```bash
simple-ca make-ca [--ca-dir DIR] [--days N] [--aia-base-url URL] [--issuing-ca NAME] CA_NAME
simple-ca make-cert [--ca-dir DIR] [--cert-dir DIR] [--days N] [--issuing-ca NAME] SUBJECT [SAN ...]
simple-ca make-pfx [--ca-dir DIR] [--issuing-ca NAME] [--password PASS] [--apple-openssl] CERT_PATH
simple-ca make-ca [--ca-dir DIR] [--days N] [--ca-publish-base-url URL] [--issuing-ca NAME] CA_NAME
simple-ca make-cert [--ca-dir DIR] [--cert-dir DIR] [--days N] [--issuing-ca NAME] [--type server|user] SUBJECT [SAN ...]
simple-ca make-pfx [--ca-dir DIR] [--issuing-ca NAME] [--password PASS] [--apple-openssl] CERT_PATH
simple-ca make-crl [--ca-dir DIR] [--issuing-ca NAME] [--days N]
simple-ca revoke-cert [--ca-dir DIR] [--issuing-ca NAME] CERT_PATH
```
`SIMPLE_CA_DIR` environment variable is used as the default CA directory when `--ca-dir` is not specified.