Files
racket-self-signed-cert/scribblings/self-signed-cert.scrbl

204 lines
4.9 KiB
Racket

#lang scribble/manual
@(require scribble/example
(for-label racket/base
racket/contract
openssl))
@title{Self-Signed Certificate Utilities}
@author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]]
@defmodule[racket-self-signed-cert]
This module provides utilities for generating a self-signed X.509 certificate
together with a corresponding private key.
The implementation uses the @racketmodname[openssl] bindings that are
distributed with Racket. In other words, the module relies on the
OpenSSL library that ships with Racket and accesses it via Racket's
FFI interface.
The generated certificate and key are returned in PEM format and can
be used directly with Racket networking libraries such as
@racketmodname[openssl] or TLS-enabled servers.
@section{OpenSSL Integration}
The module dynamically integrates with the OpenSSL library that is
present in the running Racket installation.
During initialization the module performs the following steps:
@itemlist[
@item{
It detects the major version of the OpenSSL library available through
Racket's @racketmodname[openssl] bindings.
}
@item{
If OpenSSL version 3 is detected, the module raises an error because
the required FFI bindings currently support only the OpenSSL 1.x API.
}
@item{
The module determines which native OpenSSL library must be loaded for
FFI access. This allows the implementation to bind directly to the
required cryptographic primitives.
}
@item{
Platform-specific loading of the native OpenSSL library is performed
at runtime.
}
]
The implementation has been tested on the following platforms:
@itemlist[
@item{Windows}
@item{Linux}
]
Other platforms may work provided that a compatible OpenSSL library is
available through Racket.
@section{Data Structures}
@defstruct[self-signed-cert ([private-key string?]
[certificate string?])]{
Represents a generated self-signed certificate together with its
private key.
Both fields contain PEM encoded text.
@itemlist[
@item{@racket[private-key] the RSA private key in PEM format.}
@item{@racket[certificate] the X.509 certificate in PEM format.}
]
Instances of this structure are returned by
@racket[generate-self-signed-cert].
}
@defproc[(self-signed-cert? [v any/c]) boolean?]{
Returns @racket[#t] if @racket[v] is a
@racket[self-signed-cert] structure.
}
@section{Accessors}
@defproc[(private-key [ssc self-signed-cert?]) string?]{
Returns the private key stored in @racket[ssc].
The value is a PEM encoded RSA private key suitable for use with
TLS libraries or for writing to disk.
}
@defproc[(certificate [ssc self-signed-cert?]) string?]{
Returns the X.509 certificate stored in @racket[ssc].
The value is a PEM encoded certificate.
}
@defthing[x509-cert (-> self-signed-cert? string?)]{
Alias for @racket[certificate].
This name is provided for situations where the API user prefers the
term “X.509 certificate”.
}
@section{Certificate Generation}
@defproc[(generate-self-signed-cert
[bits integer?]
[duration-in-days integer?]
[hosts (or/c is-ip? is-dns? list-of-hosts?)]
[country string?]
[company string?])
self-signed-cert?]{
Generates a new self-signed RSA certificate and private key.
The implementation uses the OpenSSL functionality provided through
Racket's @racketmodname[openssl] library.
@subsection{Arguments}
@itemlist[
@item{@racket[bits] size of the RSA key in bits (for example
@racket[2048] or @racket[4096]).}
@item{@racket[duration-in-days] number of days for which the
certificate remains valid.}
@item{@racket[hosts] a host name, IP address, or a list of such
values. These values are written into the certificate's
@italic{Subject Alternative Name} extension.}
@item{@racket[country] value for the certificate subject's
@tt{C} (country) attribute.}
@item{@racket[company] value for the certificate subject's
@tt{O} (organization) attribute.}
]
The first host in the list is used as the certificate's
Common Name (CN).
@subsection{Result}
Returns a @racket[self-signed-cert] structure containing:
@itemlist[
@item{the private RSA key}
@item{the corresponding self-signed X.509 certificate}
]
Both values are returned as PEM encoded strings.
@subsection{Example}
@#reader scribble/comment-reader
[racketblock
(define cert
(generate-self-signed-cert
2048
365
'("localhost" "127.0.0.1" "*.local.lan")
"NL"
"Example Company"))
(private-key cert)
(certificate cert)
]
The returned values can be written to files or supplied directly
to TLS-enabled servers.
}
@section{Notes}
@itemlist[
@item{
This module relies on the OpenSSL library distributed with Racket and
accessed through the @racketmodname[openssl] package.
}
@item{
Certificates are generated entirely in memory and returned as PEM
strings.
}
@item{
The Subject Alternative Name (SAN) extension is automatically populated
from the provided host names and IP addresses.
}
]