Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
205 changes: 205 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
name: Certificate Generator CI

on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
workflow_dispatch:

jobs:
test:
name: Test Certificate Generation
runs-on: ubuntu-latest

strategy:
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Display Python version
run: python --version

- name: Create virtual environment
run: make env

- name: Install dependencies
run: make install
env:
PIP_TRUSTED_HOST: "pypi.org pypi.python.org files.pythonhosted.org"

- name: Verify installation
run: |
source venv/bin/activate
pip list

- name: Test certificate generation (automated)
run: |
# Create automated input for certificate generation
cat << EOF > test_input.txt
AE
Dubai
Emaar Square
XYZ Company
Information Technology
XYZ Company Test CA
test@xyz.ae
test-server.xyz.ae
EOF

source venv/bin/activate
python digital-cert.py < test_input.txt || true
env:
DIGITAL_CERT_PASSPHRASE: test-passphrase

- name: Verify CA directory created
run: |
if [ -d "CA" ]; then
echo "✓ CA directory created successfully"
ls -la CA/
else
echo "✗ CA directory not found"
exit 1
fi

- name: Verify CA certificate and key
run: |
if [ -f "CA/ca.crt" ] && [ -f "CA/ca.key" ]; then
echo "✓ CA certificate and key created"
openssl x509 -in CA/ca.crt -text -noout | head -20
else
echo "✗ CA certificate or key not found"
exit 1
fi

- name: Verify client certificate and key
run: |
if ls *.crt *.key 1> /dev/null 2>&1; then
echo "✓ Client certificates created"
ls -la *.crt *.key
for cert in *.crt; do
echo "Checking $cert:"
openssl x509 -in $cert -text -noout | head -20
done
else
echo "✗ Client certificates not found"
exit 1
fi

- name: Validate certificate properties
run: |
echo "Validating CA certificate..."
openssl x509 -in CA/ca.crt -noout -subject -issuer -dates

echo ""
echo "Validating client certificate..."
for cert in *.crt; do
if [ "$cert" != "CA/ca.crt" ]; then
openssl x509 -in $cert -noout -subject -issuer -dates
fi
done

- name: Test certificate verification
run: |
for cert in *.crt; do
if [ "$cert" != "CA/ca.crt" ]; then
echo "Verifying $cert against CA..."
openssl verify -CAfile CA/ca.crt $cert
fi
done

- name: List all generated files
run: make list

- name: Upload certificates as artifacts
uses: actions/upload-artifact@v4
if: always()
with:
name: certificates-python-${{ matrix.python-version }}
path: |
CA/
*.crt
*.key
retention-days: 7

- name: Clean up certificates
if: always()
run: make clean

- name: Verify cleanup
run: |
if ls *.crt *.key 1> /dev/null 2>&1; then
echo "��� Client certificates not cleaned"
exit 1
else
echo "✓ Client certificates cleaned successfully"
fi

lint:
name: Code Quality Check
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"

- name: Install linting tools
run: |
python -m pip install --trusted-host pypi.org --trusted-host pypi.python.org --trusted-host files.pythonhosted.org flake8 pylint

- name: Run flake8
run: |
flake8 digital-cert.py --max-line-length=120 --ignore=E501 || true

- name: Run pylint
run: |
pylint digital-cert.py --disable=all --enable=E,F || true

security:
name: Security Scan
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"

- name: Install security tools
run: |
python -m pip install --trusted-host pypi.org --trusted-host pypi.python.org --trusted-host files.pythonhosted.org bandit safety

- name: Run bandit security scan
run: |
bandit -r . -f json -o bandit-report.json || true
bandit -r . || true

- name: Check dependencies for vulnerabilities
run: |
if [ -f requirements.txt ]; then
safety check -r requirements.txt || true
fi

- name: Upload security report
uses: actions/upload-artifact@v4
if: always()
with:
name: security-report
path: bandit-report.json
retention-days: 30
8 changes: 7 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,8 @@
.env
.vscode
.vscode
.venv/
venv/
__pycache__/
CA/
*.crt
*.key
67 changes: 67 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
PYTHON ?= python3
VENV ?= venv
PYTHON_BIN := $(VENV)/bin/python
PIP := $(PYTHON_BIN) -m pip
SCRIPT := digital-cert.py
CA_DIR := CA

.PHONY: all help env venv install cert run list check audit clean clean-all clean-artifacts clean-env

all: help

help:
@printf "Digital Certificate Generator\n\n"
@printf "Available targets:\n"
@printf " make env|venv Create the Python virtual environment\n"
@printf " make install Install project dependencies\n"
@printf " make cert|run Generate CA and client certificates\n"
@printf " make list List generated certificates\n"
@printf " make check Compile-check the Python script\n"
@printf " make audit Audit Python dependencies\n"
@printf " make clean Remove generated client certificates and keys\n"
@printf " make clean-all Remove all generated certificates including the CA\n"
@printf " make clean-env Remove the virtual environment\n"

$(PYTHON_BIN):
$(PYTHON) -m venv $(VENV)

$(VENV)/.installed: requirements.txt | $(PYTHON_BIN)
$(PIP) install --upgrade pip
$(PIP) install -r requirements.txt
touch $(VENV)/.installed

$(VENV)/.audit-installed: | $(PYTHON_BIN)
$(PIP) install pip-audit
touch $(VENV)/.audit-installed

env: venv

venv: $(PYTHON_BIN)

install: $(VENV)/.installed

cert: $(VENV)/.installed
$(PYTHON_BIN) $(SCRIPT)

run: cert

list:
@if [ -d "$(CA_DIR)" ]; then ls -lh "$(CA_DIR)"; else printf "No CA directory found\n"; fi
@ls -lh *.crt *.key 2>/dev/null || printf "No client certificates found\n"

check: $(VENV)/.installed
$(PYTHON_BIN) -m py_compile $(SCRIPT)

audit: $(VENV)/.installed $(VENV)/.audit-installed
$(PYTHON_BIN) -m pip_audit -r requirements.txt

clean:
rm -f *.crt *.key

clean-all: clean
rm -rf $(CA_DIR)

clean-artifacts: clean-all

clean-env:
rm -rf $(VENV) __pycache__
41 changes: 29 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,35 +1,52 @@
# Digital Certificate Generator

[![Certificate Generator CI](https://github.com/iquzart/python-digital-certificate/actions/workflows/ci.yml/badge.svg)](https://github.com/iquzart/python-digital-certificate/actions/workflows/ci.yml)

### About
The script created to ease the process of creating self signed certificates. It will create both CA and Server/Client certificates.
This script creates a self-signed CA and signed server/client certificates.

Version: 3
Encription: SHA256 with RSA Encription(4096 bit)
Encryption: SHA256 with RSA encryption (4096 bit)

### Security improvements
- Uses the actively maintained `cryptography` package instead of legacy `pyOpenSSL` bindings.
- Generates cryptographically secure certificate serial numbers.
- Encrypts generated private keys with a passphrase.
- Restricts private key file permissions to owner-only access.
- Sanitizes certificate output filenames to prevent path traversal.

Set `DIGITAL_CERT_PASSPHRASE` to avoid interactive passphrase prompts.

### Install

```bash
make install
```

### Create Certificate
CA cenrtificate and key will be stored under CA directory.
CA certificate and key will be stored under the `CA` directory.

```bash
python3 digital-cert.py
make run
```

### Sample output
```
Creating CA driectory
Creating CA Certificate, Please provide the values
Creating CA Certificate, please provide the values
Country Name (2 letter code) [XX]: AE
State or Province Name (full name) []: Dubai
Locality Name (eg, city) [Default City]: Emaar Square
Organization Name (eg, company) [Default Company Ltd]: XYZ Company
Organizational Unit Name (eg, section) []: Information Technology
Common Name (eg, your name or your server's hostname) []: XYZ Company SS CA
Common Name (eg, your name or your server's hostname): XYZ Company SS CA
Email Address []: email@xyz.ae
Private key passphrase:
Confirm private key passphrase:
Created CA Certificate
CA Certificate valid for 3649 days
Client Certificate CN: svc1.xyz.ae
```


```
CA digital-cert.py README.md requirements.txt svc1.xyz.ae.crt svc1.xyz.ae.key
Private key passphrase:
Confirm private key passphrase:
Created client certificate: svc1.xyz.ae.crt
Created private key: svc1.xyz.ae.key
```
Loading
Loading