-
This commit is contained in:
203
scribblings/self-signed-cert.scrbl
Normal file
203
scribblings/self-signed-cert.scrbl
Normal file
@@ -0,0 +1,203 @@
|
||||
#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")
|
||||
"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.
|
||||
}
|
||||
]
|
||||
Reference in New Issue
Block a user