Update: replace hash symlink with CA bundle for certificate verification
All checks were successful
/ test (push) Successful in 17s
All checks were successful
/ test (push) Successful in 17s
This commit is contained in:
@@ -23,7 +23,7 @@ make_ca [--days <validity_days>] [--issuing-ca <name>] <ca_directory> <ca_name>
|
|||||||
- `--days <validity_days>`: Optional. The number of days the CA certificate will be valid. Default is 3650 days (10 years).
|
- `--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`).
|
- `--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.
|
It also maintains a `ca_bundle.pem` file in the CA directory containing the root CA and any issuing CA certificates concatenated together. Use this bundle with `openssl verify -CAfile <ca_directory>/ca_bundle.pem` instead of relying on hash symlinks — this works identically on Linux, macOS, and Windows without symlink privileges.
|
||||||
|
|
||||||
### `make_cert()`
|
### `make_cert()`
|
||||||
|
|
||||||
|
|||||||
@@ -46,10 +46,10 @@ function display_certificate() {
|
|||||||
openssl x509 -in "$CERT_PATH" -noout -subject -issuer -serial -fingerprint
|
openssl x509 -in "$CERT_PATH" -noout -subject -issuer -serial -fingerprint
|
||||||
echo
|
echo
|
||||||
|
|
||||||
echo -e "\nVerifying certificate against the CA ($CA_DIR)..."
|
echo -e "\nVerifying certificate against the CA bundle ($CA_DIR/ca_bundle.pem)..."
|
||||||
|
|
||||||
# Verify the certificate against the CA
|
# Verify the certificate against the CA bundle
|
||||||
if openssl verify -CApath "$CA_DIR" "$CERT_PATH" 2>/dev/null; then
|
if openssl verify -CAfile "$CA_DIR/ca_bundle.pem" "$CERT_PATH" 2>/dev/null; then
|
||||||
echo "Certificate verification successful."
|
echo "Certificate verification successful."
|
||||||
else
|
else
|
||||||
echo "ERROR: Certificate verification failed." >&2
|
echo "ERROR: Certificate verification failed." >&2
|
||||||
|
|||||||
47
simple-ca.py
47
simple-ca.py
@@ -33,32 +33,23 @@ def _err(msg):
|
|||||||
print(f"ERROR: {msg}", file=sys.stderr)
|
print(f"ERROR: {msg}", file=sys.stderr)
|
||||||
|
|
||||||
|
|
||||||
def make_hash_link(cert_path):
|
def _rebuild_ca_bundle(ca_dir):
|
||||||
if not os.path.isfile(cert_path):
|
"""Write ca_bundle.pem = root cert + any issuing CA certs in this dir."""
|
||||||
_err(f"Certificate file {cert_path} does not exist.")
|
bundle_path = os.path.join(ca_dir, "ca_bundle.pem")
|
||||||
return False
|
parts = []
|
||||||
|
root = os.path.join(ca_dir, "ca_cert.pem")
|
||||||
cert_dir = os.path.dirname(cert_path)
|
if os.path.isfile(root):
|
||||||
try:
|
with open(root, "rb") as f:
|
||||||
result = subprocess.run(
|
parts.append(f.read())
|
||||||
["openssl", "x509", "-in", cert_path, "-noout", "-hash"],
|
for name in sorted(os.listdir(ca_dir)):
|
||||||
capture_output=True, text=True, check=True,
|
if name == "ca_cert.pem" or not name.endswith("_cert.pem"):
|
||||||
)
|
continue
|
||||||
except subprocess.CalledProcessError:
|
path = os.path.join(ca_dir, name)
|
||||||
_err(f"Failed to calculate hash for certificate {cert_path}.")
|
if os.path.isfile(path):
|
||||||
return False
|
with open(path, "rb") as f:
|
||||||
|
parts.append(f.read())
|
||||||
cert_hash = result.stdout.strip()
|
with open(bundle_path, "wb") as f:
|
||||||
if not cert_hash:
|
f.write(b"".join(parts))
|
||||||
_err(f"Failed to calculate hash for certificate {cert_path}.")
|
|
||||||
return False
|
|
||||||
|
|
||||||
link_path = os.path.join(cert_dir, f"{cert_hash}.0")
|
|
||||||
target = os.path.basename(cert_path)
|
|
||||||
if os.path.islink(link_path) or os.path.exists(link_path):
|
|
||||||
os.remove(link_path)
|
|
||||||
os.symlink(target, link_path)
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def make_ca(ca_dir, ca_name, days=3650, issuing_ca=None, aia_base_url=None):
|
def make_ca(ca_dir, ca_name, days=3650, issuing_ca=None, aia_base_url=None):
|
||||||
@@ -119,7 +110,7 @@ def make_ca(ca_dir, ca_name, days=3650, issuing_ca=None, aia_base_url=None):
|
|||||||
_err("Failed to generate CA certificate and key.")
|
_err("Failed to generate CA certificate and key.")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
make_hash_link(root_ca_cert_path)
|
_rebuild_ca_bundle(ca_dir)
|
||||||
|
|
||||||
if aia_base_url:
|
if aia_base_url:
|
||||||
with open(aia_file, "w") as f:
|
with open(aia_file, "w") as f:
|
||||||
@@ -157,7 +148,7 @@ def make_ca(ca_dir, ca_name, days=3650, issuing_ca=None, aia_base_url=None):
|
|||||||
_err("Failed to generate issuing CA certificate and key.")
|
_err("Failed to generate issuing CA certificate and key.")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
make_hash_link(ca_cert_path)
|
_rebuild_ca_bundle(ca_dir)
|
||||||
|
|
||||||
if aia_base_url:
|
if aia_base_url:
|
||||||
with open(aia_file, "w") as f:
|
with open(aia_file, "w") as f:
|
||||||
|
|||||||
32
simple-ca.sh
32
simple-ca.sh
@@ -22,19 +22,19 @@
|
|||||||
|
|
||||||
# These functions require Bash and OpenSSL to be installed on the system.
|
# These functions require Bash and OpenSSL to be installed on the system.
|
||||||
|
|
||||||
function make_hash_link() {
|
function _rebuild_ca_bundle() {
|
||||||
local CERT_PATH="$1"
|
local CA_DIR="$1"
|
||||||
if [[ ! -f "$CERT_PATH" ]]; then
|
local BUNDLE="$CA_DIR/ca_bundle.pem"
|
||||||
echo "ERROR: Certificate file $CERT_PATH does not exist." >&2
|
: > "$BUNDLE"
|
||||||
return 1
|
if [[ -f "$CA_DIR/ca_cert.pem" ]]; then
|
||||||
|
cat "$CA_DIR/ca_cert.pem" >> "$BUNDLE"
|
||||||
fi
|
fi
|
||||||
local CERT_DIR="$(dirname "$CERT_PATH")"
|
local f
|
||||||
local HASH="$(openssl x509 -in "$CERT_PATH" -noout -hash 2>/dev/null)"
|
for f in "$CA_DIR"/*_cert.pem; do
|
||||||
if [[ -z "$HASH" ]]; then
|
[[ -f "$f" ]] || continue
|
||||||
echo "ERROR: Failed to calculate hash for certificate $CERT_PATH." >&2
|
[[ "$(basename "$f")" == "ca_cert.pem" ]] && continue
|
||||||
return 1
|
cat "$f" >> "$BUNDLE"
|
||||||
fi
|
done
|
||||||
ln -sf "$(basename "$CERT_PATH")" "$CERT_DIR/${HASH}.0"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function make_ca() {
|
function make_ca() {
|
||||||
@@ -129,8 +129,8 @@ function make_ca() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Make a "hash" symlink for the CA certificate to allow OpenSSL to find it when verifying other certificates
|
# Rebuild the CA bundle (root + any issuing CAs) for use with `openssl verify -CAfile`
|
||||||
make_hash_link "$CA_DIR/$ROOT_CA_CERT"
|
_rebuild_ca_bundle "$CA_DIR"
|
||||||
|
|
||||||
if [[ -n "$AIA_BASE_URL" ]]; then
|
if [[ -n "$AIA_BASE_URL" ]]; then
|
||||||
echo "$AIA_BASE_URL" > "$CA_DIR/aia_base_url.txt"
|
echo "$AIA_BASE_URL" > "$CA_DIR/aia_base_url.txt"
|
||||||
@@ -162,8 +162,8 @@ function make_ca() {
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Make a "hash" symlink for the issuing CA certificate to allow OpenSSL to find it when verifying other certificates
|
# Rebuild the CA bundle (root + any issuing CAs) for use with `openssl verify -CAfile`
|
||||||
make_hash_link "$CA_DIR/${CA_CERT}"
|
_rebuild_ca_bundle "$CA_DIR"
|
||||||
|
|
||||||
if [[ -n "$AIA_BASE_URL" ]]; then
|
if [[ -n "$AIA_BASE_URL" ]]; then
|
||||||
echo "$AIA_BASE_URL" > "$CA_DIR/aia_base_url.txt"
|
echo "$AIA_BASE_URL" > "$CA_DIR/aia_base_url.txt"
|
||||||
|
|||||||
Reference in New Issue
Block a user