Compare commits

..

4 Commits

Author SHA1 Message Date
8bb0c62486 Update: add validation for CA name in make_ca function
All checks were successful
/ test (push) Successful in 12s
2026-03-14 16:44:38 +01:00
677e9add5b Update: add AIA URL support in make_ca and make_cert functions
All checks were successful
/ test (push) Successful in 13s
2026-03-05 07:14:37 +01:00
41106aab29 Update: modify workflow trigger to run tests on specific file changes 2026-03-05 06:36:32 +01:00
83bd2db52c Update: add README content. 2026-03-05 06:33:51 +01:00
3 changed files with 92 additions and 3 deletions

View File

@@ -1,7 +1,8 @@
on: on:
push: push:
branches: paths:
- main - 'simple-ca.sh'
- 'run-tests.sh'
jobs: jobs:
test: test:

View File

@@ -2,3 +2,56 @@
[![test](https://gitea.koszewscy.waw.pl/slawek/simple-ca/actions/workflows/test.yaml/badge.svg)](https://gitea.koszewscy.waw.pl/slawek/simple-ca/actions?workflow=test.yaml) [![test](https://gitea.koszewscy.waw.pl/slawek/simple-ca/actions/workflows/test.yaml/badge.svg)](https://gitea.koszewscy.waw.pl/slawek/simple-ca/actions?workflow=test.yaml)
`simple-ca.sh` is a Bash script that provides functions for creating and managing a simple Certificate Authority (CA) and generating certificates. It can create a single or two-level CA hierarchy, and generate client-server TLS certificates. The script is designed to be simple and easy to use, making it suitable for testing and development purposes, where a self-signed certificate is not sufficient.
All certificates generated by this script have a random serial number.
## Functions
### `make_ca()`
This function creates a root CA certificate and private key. It can optionally create an intermediate CA certificate and private key, which is signed by the root CA. The function takes several parameters to customize the CA creation process, such as the CA name, validity period, and whether to create an intermediate CA.
Usage:
```bash
make_ca [--days <validity_days>] [--issuing-ca <name>] <ca_directory> <ca_name>
```
- `<ca_directory>`: The directory where the CA files will be stored.
- `<ca_name>`: The name of the CA.
- `--days <validity_days>`: Optional. The number of days the CA certificate will be valid. Default is 3650 days (10 years).
- `--issuing-ca <name>`: Optional. If specified, creates an intermediate CA with <ca_name> as the intermediate CA name and using <name> as certificate and key file prefix for the issuing CA (instead of root's `ca`).
It also creates a *hash link* symbolic link for the CA certificate, which is required by OpenSSL when using the `verify` command with `-CApath` option.
### `make_cert()`
This function generates a certificate and private key with TLS Web Server Authentication and Client Authentication EKUs. The certificate is signed by the specified CA (either root or intermediate).
Usage:
```bash
make_cert --ca-dir <ca_directory> [--days <validity_days>] [--issuing-ca <name>] <cert_directory> <subject_name>
```
- `<ca_directory>`: The directory where the CA files are stored (used to find the CA certificate and key for signing).
- `<cert_directory>`: The directory where the generated certificate and key will be stored.
- `<subject_name>`: The subject name (Common Name) for the certificate.
- `--days <validity_days>`: Optional. The number of days the certificate will be valid. Default is 365 days.
- `--issuing-ca <name>`: Optional. If specified, uses the CA with the key `<name>_key.pem` and certificate `<name>_cert.pem` for signing instead of the root CA.
### `make_pfx()`
This function creates a PKCS#12 (PFX) file containing the certificate, private key, and CA certificate chain. This is useful for importing the certificate into applications that require a PFX file.
Usage:
```bash
make_pfx --ca-dir <ca_directory> [--issuing-ca <file_prefix>] --path <pfx_file_path> [--password <pfx_password>]
```
- `--ca-dir <ca_directory>`: The directory where the CA files are stored (used to find the CA certificate for the chain).
- `--issuing-ca <file_prefix>`: The file prefix of the issuing CA to include in the chain.
- `--path <pfx_file_path>`: The path where the generated PFX file will be saved.
- `--password <pfx_password>`: Optional. The custom password to protect the PFX, instead of the default `changeit`.

View File

@@ -42,6 +42,7 @@ function make_ca() {
# CA defaults to the main CA if not specified, but can be overridden with --issuing-ca # CA defaults to the main CA if not specified, but can be overridden with --issuing-ca
local CA_FILE_PREFIX="ca" local CA_FILE_PREFIX="ca"
local AIA_BASE_URL=""
while [[ $# -gt 0 ]]; do while [[ $# -gt 0 ]]; do
case "$1" in case "$1" in
@@ -65,6 +66,14 @@ function make_ca() {
CA_FILE_PREFIX="$2" CA_FILE_PREFIX="$2"
shift 2 shift 2
;; ;;
--aia-base-url)
if [[ -z "$2" ]]; then
echo "ERROR: Missing value for --aia-base-url." >&2
return 1
fi
AIA_BASE_URL="$2"
shift 2
;;
*) *)
break break
;; ;;
@@ -76,11 +85,20 @@ function make_ca() {
local CA_NAME="$2" local CA_NAME="$2"
shift 2 shift 2
if [[ -z "$CA_DIR" || -z "$CA_NAME" || ! -d "$CA_DIR" ]]; then if [[ -z "$CA_DIR" || ! -d "$CA_DIR" ]]; then
echo "ERROR: Certificate directory $CA_DIR does not exist." echo "ERROR: Certificate directory $CA_DIR does not exist."
return 1 return 1
fi fi
if [[ -z "$CA_NAME" ]]; then
echo "ERROR: CA name is required." >&2
return 1
fi
if [[ -z "$AIA_BASE_URL" && -f "$CA_DIR/aia_base_url.txt" ]]; then
AIA_BASE_URL="$(cat "$CA_DIR/aia_base_url.txt")"
fi
local ROOT_CA_CERT="ca_cert.pem" local ROOT_CA_CERT="ca_cert.pem"
local ROOT_CA_KEY="ca_key.pem" local ROOT_CA_KEY="ca_key.pem"
local CA_CERT="${CA_FILE_PREFIX}_cert.pem" local CA_CERT="${CA_FILE_PREFIX}_cert.pem"
@@ -113,6 +131,10 @@ function make_ca() {
# Make a "hash" symlink for the CA certificate to allow OpenSSL to find it when verifying other certificates # Make a "hash" symlink for the CA certificate to allow OpenSSL to find it when verifying other certificates
make_hash_link "$CA_DIR/$ROOT_CA_CERT" make_hash_link "$CA_DIR/$ROOT_CA_CERT"
if [[ -n "$AIA_BASE_URL" ]]; then
echo "$AIA_BASE_URL" > "$CA_DIR/aia_base_url.txt"
fi
return 0 return 0
fi fi
@@ -124,6 +146,7 @@ function make_ca() {
-noenc \ -noenc \
-subj "/CN=${CA_NAME}" \ -subj "/CN=${CA_NAME}" \
-addext "basicConstraints=critical,CA:TRUE,pathlen:0" \ -addext "basicConstraints=critical,CA:TRUE,pathlen:0" \
${AIA_BASE_URL:+-addext "authorityInfoAccess=caIssuers;URI:${AIA_BASE_URL}/ca_cert.crt"} \
| openssl x509 \ | openssl x509 \
-req \ -req \
-CA "$CA_DIR/$ROOT_CA_CERT" \ -CA "$CA_DIR/$ROOT_CA_CERT" \
@@ -140,6 +163,10 @@ function make_ca() {
# Make a "hash" symlink for the issuing CA certificate to allow OpenSSL to find it when verifying other certificates # Make a "hash" symlink for the issuing CA certificate to allow OpenSSL to find it when verifying other certificates
make_hash_link "$CA_DIR/${CA_CERT}" make_hash_link "$CA_DIR/${CA_CERT}"
if [[ -n "$AIA_BASE_URL" ]]; then
echo "$AIA_BASE_URL" > "$CA_DIR/aia_base_url.txt"
fi
return 0 return 0
} }
@@ -204,6 +231,12 @@ function make_cert() {
CA_DIR="${CA_DIR:-$CERT_DIR}" CA_DIR="${CA_DIR:-$CERT_DIR}"
local AIA_BASE_URL_FILE="$CA_DIR/aia_base_url.txt"
local AIA_URL=""
if [[ -f "$AIA_BASE_URL_FILE" ]]; then
AIA_URL="$(cat "$AIA_BASE_URL_FILE")/${CA_FILE_PREFIX}_cert.crt"
fi
local CA_CERT="${CA_FILE_PREFIX}_cert.pem" local CA_CERT="${CA_FILE_PREFIX}_cert.pem"
local CA_KEY="${CA_FILE_PREFIX}_key.pem" local CA_KEY="${CA_FILE_PREFIX}_key.pem"
@@ -271,6 +304,7 @@ function make_cert() {
-addext "keyUsage=digitalSignature,keyEncipherment" \ -addext "keyUsage=digitalSignature,keyEncipherment" \
-addext "extendedKeyUsage=serverAuth,clientAuth" \ -addext "extendedKeyUsage=serverAuth,clientAuth" \
-addext "$SANS_EXT" \ -addext "$SANS_EXT" \
${AIA_URL:+-addext "authorityInfoAccess=caIssuers;URI:${AIA_URL}"} \
| openssl x509 \ | openssl x509 \
-req \ -req \
-CA "$CA_DIR/$CA_CERT" \ -CA "$CA_DIR/$CA_CERT" \
@@ -401,3 +435,4 @@ function make_pfx() {
return 0 return 0
} }