certpy 0.1.2
Self-signed SSL certificate generator
License: MIT
Requires Python: >=3.7

# certpy

> Self-signed SSL certificate generator :closed_lock_with_key:

This tool is an experiment to learn _"How to create a self-signed certificate"_.

## Installation

With `pip`:

```
pip install certpy
```

Install from source (you need to install [python-pdm](https://pdm.fming.dev/latest/) first):

```
git clone https://github.com/aprilahijriyan/certpy.git
cd certpy
pdm install
```

## Usage

CertPy provides a workflow file, which will be used to instruct the creation of the certificate.

> The workflow file name is `certpy.yml` (you cannot change the file name or extension to `.yaml`) and the workflow file must be in the directory you are working in.

Here's an example of a workflow:

```yml
# Save it as certpy.yml in the current directory.
certificate_age: &age
  days: 365

certificates:
  kuli:
    type: ca
    distinguished_name:
      countryName: ID
      stateOrProvinceName: Indonesia
      localityName: Jawa Barat
      organizationName: Kuli Dev
      organizationalUnitName: OSS
      commonName: Kuli Dev Root CA
      emailAddress: null
    age: *age
    hash: sha256
    overwrite: true

  server:
    type: server
    distinguished_name:
      commonName: Server
    ca_file: kuli
    age: *age
    hash: sha256
    san:
      ip:
        - 192.168.18.203
      dns:
        - ca.example.com
    overwrite: true

  client:
    type: client
    distinguished_name:
      commonName: Client
    ca_file: kuli
    age: *age
    hash: sha256
    overwrite: true
```

Then, create a CertPy environment (this is to hold all certificates created by CertPy).

```sh
# this will create a `~/.certpy` directory and create a default `Root CA` certificate stored in `~/.certpy/ca/certs/rootCA.pem`.
certpy ca init
```

Now you can create your own certificate from the workflow file!

```
$ certpy create
                                  'kuli' Root CA
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ CA File                               ┃ CA Key                                  ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ /home/april/.certpy/ca/certs/kuli.pem │ /home/april/.certpy/ca/private/kuli.key │
└───────────────────────────────────────┴─────────────────────────────────────────┘
                                     'server' Certificate
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Cert File                                   ┃ Cert Key                                      ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ /home/april/.certpy/server/certs/server.pem │ /home/april/.certpy/server/private/server.key │
└─────────────────────────────────────────────┴───────────────────────────────────────────────┘
                                     'client' Certificate
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Cert File                                   ┃ Cert Key                                      ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ /home/april/.certpy/client/certs/client.pem │ /home/april/.certpy/client/private/client.key │
└─────────────────────────────────────────────┴───────────────────────────────────────────────┘
```

You can verify the self-signed certificate, using the command:

```
$ openssl verify -verbose -CAfile /home/april/.certpy/ca/certs/kuli.pem /home/april/.certpy/server/certs/server.pem
/home/april/.certpy/server/certs/server.pem: OK
```

All certificates generated by CertPy will be stored in the `~/.certpy` directory. And each type of certificate is stored in a different directory.

* For `Root CA` stored in `~/.certpy/ca`.
* For `Server Certificate` stored in `~/.certpy/server`.
* For `Client Certificate` stored in `~/.certpy/client`.

In the directory `~/.certpy/{ca,server,client}` there are 2 directories.

* The `certs` directory is used to store certificates.
* The `private` directory is used to store certificate keys.


## Workflow structure details

* About `certificates` in workflow file

    It contains the definition of certificate.
    In CertPy only supports `Root CA`, `Server` and `Client` certificate types.

    Each type of certificate has a different data structure. Read more below...

* About `Root CA` Certificate

  The structure for `Root CA` is as follows:

  * `type`: set to `ca` to mark if this is a **Root CA** certificate. (**required**)
  * `distinguished_name`: (`object`, **required**)

      * `countryName`: Country Code (e.g. `ID`) (**optional**)
      * `stateOrProvinceName`: State (e.g. `Indonesia`) (**optional**)
      * `localityName`: Province (e.g. `Jawa Barat`) (**optional**)
      * `organizationName`: Organization Name (e.g. `Kuli Dev`) (**optional**)
      * `organizationalUnitName`: Organization Unit Name (e.g. `OSS`) (**optional**)
      * `commonName`: Common Name (e.g. `Kuli Dev Root CA`) (**required**)
      * `emailAddress`: Email address (e.g. `your@company.com`) (**optional**)
  * `age`: (`object`, **required**)

      You must fill in one of the fields below. For example fill `days` with `365` (which is a certificate valid in 1 year)

      * `days`
      * `seconds`
      * `microseconds`
      * `milliseconds`
      * `minutes`
      * `hours`
      * `weeks`

  * `hash`: See https://www.pyopenssl.org/en/latest/api/crypto.html#digest-names (**required**)
  * `overwrite`: If it is set to `true` it will overwrite the old certificate with the new one. By default, if the certificate already exists it will be skipped. (`bool`, **optional**)

* About `Server` Certificate

  Its structure is the same as `Root CA`.

  However, there is a slight addition to the `Server` certificate. Here's a list of the new fields in the `server` certificate:

  * `ca_file`: (`str` or `array`, **required**)

    The CA file is required to sign certificates for `server` or `client`.

    - If it is `str`, it will use the `Root CA` certificate from the workflow file.
    - If using `array`, must have 2 items. For example index `0` is `CA File` and index `1` is `CA Key`.

  * `san`: (`object`, **required**)

    * `ip`: IP address list (`array`)
    * `dns`: Domain name list (`array`)

  > Note: the certificate must be marked with `type: server` if you want to create a certificate for `Server`.

* About `Client` Certificate

  Its structure is the same as `Server Certificate`.

  However, on the client certificate it doesn't have a `san` field.

  > Note: the certificate must be marked with `type: client` if you want to create a certificate for `Client`.

## Related projects

CertPy is heavily inspired by the following tools:

* [mkcert](https://github.com/FiloSottile/mkcert)
* [step-cli](https://smallstep.com/)