Skip to content

Commit

Permalink
Doc clarifications
Browse files Browse the repository at this point in the history
  • Loading branch information
tsaarni committed May 31, 2023
1 parent d078b40 commit d10e951
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 32 deletions.
6 changes: 5 additions & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,19 @@
"sphinx_rtd_theme",
]


templates_path = ["_templates"]
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]

# Adds links to Python standard library and cryptography documentation.
intersphinx_mapping = {
"python": ("https://docs.python.org/3", None),
"cryptography": ("https://cryptography.io/en/latest/", None),
}

autodoc_default_options = {
"no-value": True, # Hide enum values
}

# -- Options for HTML output -------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output

Expand Down
25 changes: 16 additions & 9 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,25 +19,32 @@ Install certy from `pypi`_
Examples
========

Write certificates to files
---------------------------
Basics: issuing certificates
----------------------------

Following example creates a CA certificate and a server certificate signed by the CA.
The server certificate is valid for host ``app.127.0.0.1.nip.io``.
Following example creates a CA certificate, a server certificate signed by the CA and writes them to files.

.. literalinclude:: ../examples/write-ca-and-server-cert.py
:linenos:

Given defaults are OK for typical use, which makes simple use very simple:

HTTPS server and client
-----------------------
* CA certificate will automatically include basic constrains extension with CA field set. It is recognized as CA, because ``ca.issuer()`` was not called.
* Server certificate is recognized as end-entity certificate, since it was signed by the CA - ``server.issuer(ca)`` was called.
* Key usage is set according to the certificate type: CA certificates are allowed to sign other certificates, end-entity certificates are allowed to be used for TLS server and client authentication.
* The ``validFrom`` and ``validTo`` fields are set to current time and one year in the future, respectively.
* ``EC`` key type of 256 bits is used.
* Serial number is randomly generated.

Complete example: HTTPS server and client
-----------------------------------------

Following example creates two PKI hierarchies:

* The server PKI hierarchy contains a root CA and intermediate CA. The server certificate is signed by the intermediate.
* The client PKI hierarchy contains just a root CA, which is used to sign the client certificate.

The server validates the client certificate against the client root CA and the client validates the server certificate against the server root CA.
The HTTP server validates the client certificate against the client root CA and the client validates the server certificate against the server root CA.
The client also validates that the server hostname matches the certificate subject alternative name ``app.127.0.0.1.nip.io`` since that hostname is used to connect to the server.

.. literalinclude:: ../examples/https-server-and-client.py
Expand All @@ -51,8 +58,8 @@ API Reference
:undoc-members:


Bugs, feature requests and other contributions
==============================================
Bugs reports, feature requests and other contributions
======================================================

Please use the `github`_ project for reporting bugs, requesting features and submitting pull requests.

Expand Down
8 changes: 6 additions & 2 deletions examples/https-server-and-client.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

def serve_https(server_cert_path, server_key_path, client_root_ca_path):
# Create SSLContext for the server.
# Require client certificate signed by the client root CA.
# Require client to present certificate, signed by the client root CA.
context = ssl.create_default_context(
ssl.Purpose.CLIENT_AUTH, cafile=client_root_ca_path
)
Expand All @@ -26,6 +26,8 @@ def serve_https(server_cert_path, server_key_path, client_root_ca_path):

# Create root CA and intermediate CA for issuing server certificate.
server_root_ca_cred = Credential().subject("CN=server-root-ca")
# Certy does not recognize intermediate CA as CA since it is not self-signed.
# ca() needs to be called explicitly to prepare the certificate as CA cert.
server_intermediate_ca_cred = (
Credential().subject("CN=server-intermediate-ca").issuer(server_root_ca_cred).ca()
)
Expand All @@ -46,7 +48,9 @@ def serve_https(server_cert_path, server_key_path, client_root_ca_path):

# Write the certificates and keys to disk.
server_root_ca_cred.write_certificates_as_pem("server-root-ca.pem")
server_cred.write_certificates_as_pem("server.pem")
server_cred.write_certificates_as_pem(
"server.pem"
) # server.pem bundle includes chain: server cert, intermediate CA (in that order).
server_cred.write_private_key_as_pem("server-key.pem")
client_root_ca_cred.write_certificates_as_pem("client-root-ca.pem")
client_cred.write_certificates_as_pem("client.pem")
Expand Down
7 changes: 1 addition & 6 deletions examples/write-ca-and-server-cert.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,6 @@
ca = Credential().subject("CN=ca")
ca.write_certificates_as_pem("ca.pem")

cred = (
Credential()
.subject("CN=server")
.issuer(ca)
.subject_alt_names("DNS:app.127.0.0.1.nip.io")
)
cred = Credential().subject("CN=server").issuer(ca)
cred.write_certificates_as_pem("cert.pem")
cred.write_private_key_as_pem("key.pem")
34 changes: 20 additions & 14 deletions src/certy/credential.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,17 @@ class ExtendedKeyUsage(Enum):
"""Extended key usages are used with :meth:`Credential.ext_key_usages` to specify the extended key usages for the certificate."""

SERVER_AUTH = ExtendedKeyUsageOID.SERVER_AUTH
"""Certificate can be used as TLS server certificate."""
CLIENT_AUTH = ExtendedKeyUsageOID.CLIENT_AUTH
"""Certificate can be used as TLS client certificate."""
CODE_SIGNING = ExtendedKeyUsageOID.CODE_SIGNING
"""Certificate can be used for code signing."""
EMAIL_PROTECTION = ExtendedKeyUsageOID.EMAIL_PROTECTION
"""Certificate can be used for email protection (signing, encryption, key agreement)."""
TIME_STAMPING = ExtendedKeyUsageOID.TIME_STAMPING
"""Certificate can be used to bind the hash of an object to a time from a trusted time source."""
OCSP_SIGNING = ExtendedKeyUsageOID.OCSP_SIGNING
"""Private key associated to certificate can be used to sign OCSP response."""


class Credential(object):
Expand Down Expand Up @@ -85,10 +91,10 @@ def __repr__(self):
def ca(self, ca: bool = True) -> Credential:
"""Set whether this credential is a CA or not.
If CA is set to ``True``, the key usage ``KeyUsage.KEY_CERT_SIGN`` and ``KeyUsage.CRL_SIGN`` are set
to the certificate, and the basic constraints extension is included with ``ca`` field set to ``True``.
If CA is set to :const:`True`, the key usage :const:`KeyUsage.KEY_CERT_SIGN` and :const:`KeyUsage.CRL_SIGN` are set
to the certificate, and the basic constraints extension is included with ``ca`` field set to :const:`True``.
If not called, ``True`` is used for credentials that are self-signed, ``False`` for credentials that are not.
If not called, :const:`True` is used for credentials that are self-signed, :const:`False` for credentials that are not.
:param ca: Whether this credential is a CA or not.
:type ca: bool
Expand Down Expand Up @@ -149,9 +155,9 @@ def issuer(self, issuer: Credential) -> Credential:
def key_type(self, key_type: KeyType) -> Credential:
"""Set the key type of this credential.
If not called, the key type will be :data:`KeyType.EC`.
If not called, the key type will be :const:`KeyType.EC`.
:param key_type: The key type of this credential. Must be :data:`KeyType.EC` or :data:`KeyType.RSA`.
:param key_type: The key type of this credential. Must be :const:`KeyType.EC` or :const:`KeyType.RSA`.
:type key_type: KeyType
:return: This credential instance.
:rtype: Credential
Expand All @@ -164,7 +170,7 @@ def key_type(self, key_type: KeyType) -> Credential:
def key_size(self, key_size: int) -> Credential:
"""Set the key size of this credential.
If not called, the key size is ``256`` for :data:`KeyType.EC` and ``2048`` for :data:`KeyType.RSA`.
If not called, the key size is ``256`` for :const:`KeyType.EC` and ``2048`` for :const:`KeyType.RSA`.
:param key_size: The key size of this credential. Valid values depend on the key type.
For EC keys, valid values are 256, 384, and 521.
Expand Down Expand Up @@ -248,11 +254,11 @@ def serial(self, serial: int) -> Credential:
def key_usages(self, *key_usages: KeyUsage) -> Credential:
"""Set the key usages of this credential.
If not called, the key usages ``KeyUsage.DIGITAL_SIGNATURE`` and ``KeyUsage.KEY_ENCIPHERMENT`` are set
to end-entity certificates (:meth:`ca` is not ``False``), and ``KeyUsage.KEY_CERT_SIGN`` and
``KeyUsage.CRL_SIGN`` are set to CA certificates (:meth:`ca` is ``True``).
If not called, the key usages :const:`KeyUsage.DIGITAL_SIGNATURE` and :const:`KeyUsage.KEY_ENCIPHERMENT` are set
to end-entity certificates (:meth:`ca` is not :const:`False`), and :const:`KeyUsage.KEY_CERT_SIGN` and
:const:`KeyUsage.CRL_SIGN` are set to CA certificates (:meth:`ca` is :const:`True`).
:param key_usages: The key usages of this credential. One or more of :data:`certy.KeyUsage`.
:param key_usages: The key usages of this credential. One or more of :const:`KeyUsage`.
:type key_usages: tuple[certy.KeyUsage]
:return: This credential instance.
:rtype: Credential
Expand All @@ -268,7 +274,7 @@ def ext_key_usages(self, *ext_key_usages: ExtendedKeyUsage) -> Credential:
If not called, extended key usages extension is not be included in the certificate.
:param ext_key_usages: The extended key usages of this credential. One or more of certy.ExtendedKeyUsage.
:param ext_key_usages: The extended key usages of this credential. One or more of :const:`ExtendedKeyUsage`.
:type ext_key_usages: tuple[ExtendedKeyUsage]
:return: This credential instance.
:rtype: Credential
Expand Down Expand Up @@ -455,12 +461,12 @@ def get_private_key(self) -> rsa.RSAPrivateKey | ec.EllipticCurvePrivateKey:
return self._private_key # type: ignore

def get_private_key_as_pem(self, password: str | None = None) -> bytes:
"""Get the private key in PKCS8 PEM format.
"""Get the private key in PKCS#8 PEM format.
If the private key has not been generated yet by calling :meth:`generate`, it is generated automatically.
:param password: The password to encrypt the private key with. If not set, the private key is not encrypted.
:return: The private key in PKCS8 PEM format.
:return: The private key in PKCS#8 PEM format.
:rtype: bytes
"""
self._ensure_generated()
Expand Down Expand Up @@ -511,7 +517,7 @@ def write_certificates_as_pem(self, path: str) -> Credential:
def write_private_key_as_pem(
self, path: str, password: str | None = None
) -> Credential:
"""Write the private key in PKCS8 PEM format to a file.
"""Write the private key in PKCS#8 PEM format to a file.
If the private key has not been generated yet by calling :meth:`generate`, it is generated automatically.
Expand Down

0 comments on commit d10e951

Please sign in to comment.