955 lines
42 KiB
ReStructuredText
955 lines
42 KiB
ReStructuredText
.. _x509_certificates:
|
|
|
|
X.509 Certificates and CRLs
|
|
=================================
|
|
|
|
A certificate is a binding between some identifying information
|
|
(called a *subject*) and a public key. This binding is asserted by a
|
|
signature on the certificate, which is placed there by some authority
|
|
(the *issuer*) that at least claims that it knows the subject named in
|
|
the certificate really "owns" the private key corresponding to the
|
|
public key in the certificate.
|
|
|
|
The major certificate format in use today is X.509v3, used for instance in the
|
|
:doc:`tls` protocol. A X.509 certificate is represented by the class
|
|
``X509_Certificate``. The data of an X.509 certificate is stored as a
|
|
``shared_ptr`` to a structure containing the decoded information. So copying
|
|
``X509_Certificate`` objects is quite cheap.
|
|
|
|
|
|
.. cpp:class:: X509_Certificate
|
|
|
|
.. cpp:function:: X509_Certificate(const std::string& filename)
|
|
|
|
Load a certificate from a file. PEM or DER is accepted.
|
|
|
|
.. cpp:function:: X509_Certificate(const std::vector<uint8_t>& in)
|
|
|
|
Load a certificate from a byte string.
|
|
|
|
.. cpp:function:: X509_Certificate(DataSource& source)
|
|
|
|
Load a certificate from an abstract ``DataSource``.
|
|
|
|
.. cpp:function:: X509_DN subject_dn() const
|
|
|
|
Returns the distinguished name (DN) of the certificate's subject. This is
|
|
the primary place where information about the subject of the certificate is
|
|
stored. However "modern" information that doesn't fit in the X.500
|
|
framework, such as DNS name, email, IP address, or XMPP address, appears
|
|
instead in the subject alternative name.
|
|
|
|
.. cpp:function:: X509_DN issuer_dn() const
|
|
|
|
Returns the distinguished name (DN) of the certificate's issuer, ie the CA
|
|
that issued this certificate.
|
|
|
|
.. cpp:function:: const AlternativeName& subject_alt_name() const
|
|
|
|
Return the subjects alternative name. This is used to store
|
|
values like associated URIs, DNS addresses, and email addresses.
|
|
|
|
.. cpp:function:: const AlternativeName& issuer_alt_name() const
|
|
|
|
Return alternative names for the issuer.
|
|
|
|
.. cpp:function:: std::unique_ptr<Public_Key> load_subject_public_key() const
|
|
|
|
Deserialize the stored public key and return a new object. This
|
|
might throw, if it happens that the public key object stored in
|
|
the certificate is malformed in some way, or in the case that the
|
|
public key algorithm used is not supported by the library.
|
|
|
|
See :ref:`serializing_public_keys` for more information about what to do
|
|
with the returned object. It may be any type of key, in principle, though
|
|
RSA and ECDSA are most common.
|
|
|
|
.. cpp:function:: std::vector<uint8_t> subject_public_key_bits() const
|
|
|
|
Return the binary encoding of the subject public key. This value (or a hash of
|
|
it) is used in various protocols, eg for public key pinning.
|
|
|
|
.. cpp:function:: AlgorithmIdentifier subject_public_key_algo() const
|
|
|
|
Return an algorithm identifier that identifies the algorithm used in the
|
|
subject's public key.
|
|
|
|
.. cpp:function:: std::vector<uint8_t> serial_number() const
|
|
|
|
Return the certificates serial number. The tuple of issuer DN and
|
|
serial number should be unique.
|
|
|
|
.. cpp:function:: std::vector<uint8> raw_subject_dn() const
|
|
|
|
Return the binary encoding of the subject DN.
|
|
|
|
.. cpp:function:: std::vector<uint8> raw_issuer_dn() const
|
|
|
|
Return the binary encoding of the issuer DN.
|
|
|
|
.. cpp:function:: X509_Time not_before() const
|
|
|
|
Returns the point in time the certificate becomes valid
|
|
|
|
.. cpp:function:: X509_Time not_after() const
|
|
|
|
Returns the point in time the certificate expires
|
|
|
|
.. cpp:function:: const Extensions& v3_extensions() const
|
|
|
|
Returns all extensions of this certificate. You can use this
|
|
to examine any extension data associated with the certificate,
|
|
including custom extensions the library doesn't know about.
|
|
|
|
.. cpp:function:: std::vector<uint8_t> authority_key_id() const
|
|
|
|
Return the authority key id, if set. This is an arbitrary string; in the
|
|
issuing certificate this will be the subject key id.
|
|
|
|
.. cpp:function:: std::vector<uint8_t> subject_key_id() const
|
|
|
|
Return the subject key id, if set.
|
|
|
|
.. cpp:function:: bool allowed_extended_usage(const OID& usage) const
|
|
|
|
Return true if and only if the usage OID appears in the extended key usage
|
|
extension. Also will return true if the extended key usage extension is
|
|
not used in the current certificate.
|
|
|
|
.. cpp:function:: std::vector<OID> extended_key_usage() const
|
|
|
|
Return the list of extended key usages. May be empty.
|
|
|
|
.. cpp:function:: std::string fingerprint(const std::string& hash_fn = "SHA-1") const
|
|
|
|
Return a fingerprint for the certificate, which is basically just a hash
|
|
of the binary contents. Normally SHA-1 or SHA-256 is used, but any hash
|
|
function is allowed.
|
|
|
|
.. cpp:function:: Key_Constraints constraints() const
|
|
|
|
Returns a basic list of constraints which govern usage of the
|
|
key embedded in this certificate.
|
|
|
|
The Key_Constraints is a class that behaves somewhat like an
|
|
``enum``. The easiest way to use it is with its ``includes``
|
|
method. For example::
|
|
|
|
constraints().includes(Key_Constraints::DigitalSignature)
|
|
|
|
checks if the certificate key is valid for generating digital
|
|
signatures.
|
|
|
|
.. cpp:function:: bool matches_dns_name(const std::string& name) const
|
|
|
|
Check if the certificate's subject alternative name DNS fields
|
|
match ``name``. This function also handles wildcard certificates.
|
|
|
|
.. cpp:function:: std::string to_string() const
|
|
|
|
Returns a free-form human readable string describing the certificate.
|
|
|
|
.. cpp:function:: std::string PEM_encode() const
|
|
|
|
Returns the PEM encoding of the certificate
|
|
|
|
.. cpp:function:: std::vector<uint8_t> BER_encode() const
|
|
|
|
Returns the DER/BER encoding of the certificate
|
|
|
|
X.509 Distinguished Names
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
.. cpp:class:: X509_DN
|
|
|
|
.. cpp:function:: bool has_field(const std::string& attr) const
|
|
|
|
Returns true if ``get_attribute`` or ``get_first_attribute`` will return a value.
|
|
|
|
.. cpp:function:: std::vector<std::string> get_attribute(const std::string& attr) const
|
|
|
|
Return all attributes associated with a certain attribute type.
|
|
|
|
.. cpp:function:: std::string get_first_attribute(const std::string& attr) const
|
|
|
|
Like ``get_attribute`` but returns just the first attribute, or
|
|
empty if the DN has no attribute of the specified type.
|
|
|
|
.. cpp:function:: std::multimap<OID, std::string> get_attributes() const
|
|
|
|
Get all attributes of the DN. The OID maps to a DN component such as
|
|
2.5.4.10 ("Organization"), and the strings are UTF-8 encoded.
|
|
|
|
.. cpp:function:: std::multimap<std::string, std::string> contents() const
|
|
|
|
Similar to ``get_attributes``, but the OIDs are decoded to strings.
|
|
|
|
.. cpp:function:: void add_attribute(const std::string& key, const std::string& val)
|
|
|
|
Add an attribute to a DN.
|
|
|
|
.. cpp:function:: void add_attribute(const OID& oid, const std::string& val)
|
|
|
|
Add an attribute to a DN using an OID instead of string-valued attribute type.
|
|
|
|
The ``X509_DN`` type also supports iostream extraction and insertion operators,
|
|
for formatted input and output.
|
|
|
|
X.509v3 Extensions
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
X.509v3 specifies a large number of possible extensions. Botan supports some,
|
|
but by no means all of them. The following listing lists which X.509v3
|
|
extensions are supported and notes areas where there may be problems with the
|
|
handling.
|
|
|
|
- Key Usage and Extended Key Usage: No problems known.
|
|
|
|
- Basic Constraints: No problems known. A self-signed v1 certificate
|
|
is assumed to be a CA, while a v3 certificate is marked as a CA if
|
|
and only if the basic constraints extension is present and set for
|
|
a CA cert.
|
|
|
|
- Subject Alternative Names: Only the "rfc822Name", "dNSName", and
|
|
"uniformResourceIdentifier" and raw IPv4 fields will be stored; all
|
|
others are ignored.
|
|
|
|
- Issuer Alternative Names: Same restrictions as the Subject
|
|
Alternative Names extension. New certificates generated by Botan
|
|
never include the issuer alternative name.
|
|
|
|
- Authority Key Identifier: Only the version using KeyIdentifier is
|
|
supported. If the GeneralNames version is used and the extension is
|
|
critical, an exception is thrown. If both the KeyIdentifier and GeneralNames
|
|
versions are present, then the KeyIdentifier will be used, and the
|
|
GeneralNames ignored.
|
|
|
|
- Subject Key Identifier: No problems known.
|
|
|
|
- Name Constraints: No problems known (though encoding is not supported).
|
|
|
|
Any unknown critical extension in a certificate will lead to an
|
|
exception during path validation.
|
|
|
|
Extensions are handled by a special class taking care of encoding
|
|
and decoding. It also supports encoding and decoding of custom extensions.
|
|
To do this, it internally keeps two lists of extensions. Different lookup
|
|
functions are provided to search them.
|
|
|
|
.. note::
|
|
|
|
Validation of custom extensions during path validation is currently not supported.
|
|
|
|
.. cpp:class:: Extensions
|
|
|
|
.. cpp:function:: void add(Certificate_Extension* extn, bool critical = false)
|
|
|
|
Adds a new extension to the extensions object. If an extension of the same
|
|
type already exists, ``extn`` will replace it. If ``critical`` is true the
|
|
extension will be marked as critical in the encoding.
|
|
|
|
.. cpp:function:: bool add_new(Certificate_Extension* extn, bool critical = false)
|
|
|
|
Like ``add`` but an existing extension will not be replaced. Returns true if the
|
|
extension was used, false if an extension of the same type was already in place.
|
|
|
|
.. cpp:function:: void replace(Certificate_Extension* extn, bool critical = false)
|
|
|
|
Adds an extension to the list or replaces it, if the same
|
|
extension was already added
|
|
|
|
.. cpp:function:: std::unique_ptr<Certificate_Extension> get(const OID& oid) const
|
|
|
|
Searches for an extension by OID and returns the result
|
|
|
|
.. cpp:function:: template<typename T> \
|
|
std::unique_ptr<T> get_raw(const OID& oid)
|
|
|
|
Searches for an extension by OID and returns the result.
|
|
Only the unknown extensions, that is, extensions types that are not
|
|
listed above, are searched for by this function.
|
|
|
|
.. cpp:function:: std::vector<std::pair<std::unique_ptr<Certificate_Extension>, bool>> extensions() const
|
|
|
|
Returns the list of extensions together with the corresponding
|
|
criticality flag. Only contains the supported extension types
|
|
listed above.
|
|
|
|
.. cpp:function:: std::map<OID, std::pair<std::vector<uint8_t>, bool>> extensions_raw() const
|
|
|
|
Returns the list of extensions as raw, encoded bytes
|
|
together with the corresponding criticality flag.
|
|
Contains all extensions, known as well as unknown extensions.
|
|
|
|
Certificate Revocation Lists
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
It will occasionally happen that a certificate must be revoked before
|
|
its expiration date. Examples of this happening include the private
|
|
key being compromised, or the user to which it has been assigned
|
|
leaving an organization. Certificate revocation lists are an answer to
|
|
this problem (though online certificate validation techniques are
|
|
starting to become somewhat more popular). Every once in a while the
|
|
CA will release a new CRL, listing all certificates that have been
|
|
revoked. Also included is various pieces of information like what time
|
|
a particular certificate was revoked, and for what reason. In most
|
|
systems, it is wise to support some form of certificate revocation,
|
|
and CRLs handle this easily.
|
|
|
|
For most users, processing a CRL is quite easy. All you have to do is
|
|
call the constructor, which will take a filename (or a
|
|
``DataSource&``). The CRLs can either be in raw BER/DER, or in PEM
|
|
format; the constructor will figure out which format without any extra
|
|
information. For example::
|
|
|
|
X509_CRL crl1("crl1.der");
|
|
|
|
DataSource_Stream in("crl2.pem");
|
|
X509_CRL crl2(in);
|
|
|
|
After that, pass the ``X509_CRL`` object to a ``Certificate_Store`` object
|
|
with
|
|
|
|
.. cpp:function:: void Certificate_Store::add_crl(const X509_CRL& crl)
|
|
|
|
and all future verifications will take into account the provided CRL.
|
|
|
|
Certificate Stores
|
|
----------------------------------------
|
|
|
|
An object of type ``Certificate_Store`` is a generalized interface to
|
|
an external source for certificates (and CRLs). Examples of such a
|
|
store would be one that looked up the certificates in a SQL database,
|
|
or by contacting a CGI script running on a HTTP server. There are
|
|
currently three mechanisms for looking up a certificate, and one for
|
|
retrieving CRLs. By default, most of these mechanisms will return an
|
|
empty ``std::optional`` of ``X509_Certificate``. This storage mechanism
|
|
is *only* queried when doing certificate validation: it allows you to
|
|
distribute only the root key with an application, and let some online
|
|
method handle getting all the other certificates that are needed to
|
|
validate an end entity certificate. In particular, the search routines
|
|
will not attempt to access the external database.
|
|
|
|
The certificate lookup methods are ``find_cert`` (by Subject
|
|
Distinguished Name and optional Subject Key Identifier) and
|
|
``find_cert_by_pubkey_sha1`` (by SHA-1 hash of the certificate's
|
|
public key). The Subject Distinguished Name is given as a ``X509_DN``,
|
|
while the SKID parameter takes a ``std::vector<uint8_t>`` containing
|
|
the subject key identifier in raw binary. Both lookup methods are
|
|
mandatory to implement.
|
|
|
|
Finally, there is a method for finding a CRL, called ``find_crl_for``,
|
|
that takes an ``X509_Certificate`` object, and returns a
|
|
``std::optional`` of ``X509_CRL``. The ``std::optional`` return
|
|
type makes it easy to return no CRLs by returning ``nullopt``
|
|
(eg, if the certificate store doesn't support retrieving CRLs).
|
|
Implementing the function is optional, and by default will return
|
|
``nullopt``.
|
|
|
|
Certificate stores are used in the :doc:`tls` module to store a
|
|
list of trusted certificate authorities.
|
|
|
|
.. note::
|
|
|
|
In the 2.x library, the certificate store interface relied on
|
|
``shared_ptr<X509_Certificate>`` to avoid copies. However since
|
|
2.4.0, the ``X509_Certificate`` was internally shared, and thus the
|
|
outer ``shared_ptr`` was just a cause of needless runtime overhead
|
|
and API complexity. Starting in version 3.0, the certificate store
|
|
interface is defined in terms of plain ``X509_Certificate``.
|
|
|
|
In Memory Certificate Store
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
The in memory certificate store keeps all objects in memory only.
|
|
Certificates can be loaded from disk initially, but also added
|
|
later.
|
|
|
|
.. cpp:class:: Certificate_Store_In_Memory
|
|
|
|
.. cpp:function:: Certificate_Store_In_Memory(const std::string& dir)
|
|
|
|
Attempt to parse all files in ``dir`` (including subdirectories)
|
|
as certificates. Ignores errors.
|
|
|
|
.. cpp:function:: Certificate_Store_In_Memory(const X509_Certificate& cert)
|
|
|
|
Adds given certificate to the store
|
|
|
|
.. cpp:function:: Certificate_Store_In_Memory()
|
|
|
|
Create an empty store
|
|
|
|
.. cpp:function:: void add_certificate(const X509_Certificate& cert)
|
|
|
|
Add a certificate to the store
|
|
|
|
.. cpp:function:: void add_crl(const X509_CRL& crl)
|
|
|
|
Add a certificate revocation list (CRL) to the store.
|
|
|
|
System Certificate Stores
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
An interface to use the system provided certificate stores is available for
|
|
Unix, macOS and Windows systems, ``System_Certificate_Store``
|
|
|
|
Flatfile Certificate Stores
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
``Flatfile_Certificate_Store`` is an implementation of certificate store that
|
|
reads certificates as files from a directory. This is also used as the
|
|
implementation of the Unix/Linux system certificate store.
|
|
|
|
The constructor takes a path to the directory to read, along with an optional
|
|
boolean indicating if non-CA certificates should be ignored.
|
|
|
|
SQL-backed Certificate Stores
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
The SQL-backed certificate stores store all objects in an SQL database. They
|
|
also additionally provide private key storage and revocation of individual
|
|
certificates.
|
|
|
|
.. cpp:class:: Certificate_Store_In_SQL
|
|
|
|
.. cpp:function:: Certificate_Store_In_SQL(const std::shared_ptr<SQL_Database> db, \
|
|
const std::string& passwd, RandomNumberGenerator& rng, const std::string& table_prefix = "")
|
|
|
|
Create or open an existing certificate store from an SQL database.
|
|
The password in ``passwd`` will be used to encrypt private keys.
|
|
|
|
.. cpp:function:: bool insert_cert(const X509_Certificate& cert)
|
|
|
|
Inserts ``cert`` into the store. Returns `false` if the certificate is
|
|
already known and `true` if insertion was successful.
|
|
|
|
.. cpp:function:: remove_cert(const X509_Certificate& cert)
|
|
|
|
Removes ``cert`` from the store. Returns `false` if the certificate could not
|
|
be found and `true` if removal was successful.
|
|
|
|
.. cpp:function:: std::shared_ptr<const Private_Key> find_key(const X509_Certificate&) const
|
|
|
|
Returns the private key for "cert" or an empty shared_ptr if none was found
|
|
|
|
.. cpp:function:: std::vector<X509_Certificate> find_certs_for_key(const Private_Key& key) const
|
|
|
|
Returns all certificates for private key ``key``
|
|
|
|
.. cpp:function:: bool insert_key(const X509_Certificate& cert, const Private_Key& key)
|
|
|
|
Inserts ``key`` for ``cert`` into the store, returns `false` if the key is
|
|
already known and `true` if insertion was successful.
|
|
|
|
.. cpp:function:: void remove_key(const Private_Key& key)
|
|
|
|
Removes ``key`` from the store
|
|
|
|
.. cpp:function:: void revoke_cert(const X509_Certificate&, CRL_Code, \
|
|
const X509_Time& time = X509_Time())
|
|
|
|
Marks ``cert`` as revoked starting from ``time``
|
|
|
|
.. cpp:function:: void affirm_cert(const X509_Certificate&)
|
|
|
|
Reverses the revocation for ``cert``
|
|
|
|
.. cpp:function:: std::vector<X509_CRL> generate_crls() const
|
|
|
|
Generates CRLs for all certificates marked as revoked.
|
|
A CRL is returned for each unique issuer DN.
|
|
|
|
The ``Certificate_Store_In_SQL`` class operates on an abstract ``SQL_Database``
|
|
object. If support for sqlite3 was enabled at build time, Botan includes an
|
|
implementation of this interface for sqlite3, and a subclass of
|
|
``Certificate_Store_In_SQL`` which creates or opens a sqlite3 database.
|
|
|
|
.. cpp:class:: Certificate_Store_In_SQLite
|
|
|
|
.. cpp:function:: Certificate_Store_In_SQLite(const std::string& db_path, \
|
|
const std::string& passwd, RandomNumberGenerator& rng, const std::string& table_prefix = "")
|
|
|
|
Create or open an existing certificate store from an sqlite database file.
|
|
The password in ``passwd`` will be used to encrypt private keys.
|
|
|
|
Path Validation
|
|
----------------------------------------
|
|
|
|
The process of validating a certificate chain up to a trusted root is
|
|
called `path validation`, and in botan that operation is handled by a
|
|
set of functions in ``x509path.h`` named ``x509_path_validate``:
|
|
|
|
.. cpp:function:: Path_Validation_Result \
|
|
x509_path_validate(const X509_Certificate& end_cert, \
|
|
const Path_Validation_Restrictions& restrictions, \
|
|
const Certificate_Store& store, const std::string& hostname = "", \
|
|
Usage_Type usage = Usage_Type::UNSPECIFIED, \
|
|
std::chrono::system_clock::time_point validation_time = std::chrono::system_clock::now(), \
|
|
std::chrono::milliseconds ocsp_timeout = std::chrono::milliseconds(0), \
|
|
const std::vector<std::optional<OCSP::Response>>& ocsp_resp = std::vector<std::optional<OCSP::Response>>())
|
|
|
|
The last five parameters are optional. ``hostname`` specifies a hostname which is
|
|
matched against the subject DN in ``end_cert`` according to RFC 6125.
|
|
An empty hostname disables hostname validation.
|
|
``usage`` specifies key usage restrictions that are compared
|
|
to the key usage fields in `end_cert` according to RFC 5280, if not set to
|
|
``UNSPECIFIED``. ``validation_time`` allows setting the time point at which all certificates
|
|
are validated. This is really only useful for testing. The default is the
|
|
current system clock's current time. ``ocsp_timeout`` sets the timeout for
|
|
OCSP requests. The default of 0 disables OCSP checks completely.
|
|
``ocsp_resp`` allows adding additional OCSP responses retrieved from outside
|
|
of the path validation. Note that OCSP online checks are done only
|
|
as long as the http_util module was compiled in. Availability of online
|
|
OCSP checks can be checked using the macro BOTAN_HAS_ONLINE_REVOCATION_CHECKS.
|
|
|
|
For the different flavors of ``x509_path_validate``, check ``x509path.h``.
|
|
|
|
The result of the validation is returned as a class:
|
|
|
|
.. cpp:class:: Path_Validation_Result
|
|
|
|
Specifies the result of the validation
|
|
|
|
.. cpp:function:: bool successful_validation() const
|
|
|
|
Returns true if a certificate path from *end_cert* to a trusted
|
|
root was found and all path validation checks passed.
|
|
|
|
.. cpp:function:: std::string result_string() const
|
|
|
|
Returns a descriptive string of the validation status (for
|
|
instance "Verified", "Certificate is not yet valid", or
|
|
"Signature error"). This is the string value of
|
|
the `result` function below.
|
|
|
|
.. cpp:function:: const X509_Certificate& trust_root() const
|
|
|
|
If the validation was successful, returns the certificate which
|
|
is acting as the trust root for *end_cert*.
|
|
|
|
.. cpp:function:: const std::vector<X509_Certificate>& cert_path() const
|
|
|
|
Returns the full certificate path starting with the end entity
|
|
certificate and ending in the trust root.
|
|
|
|
.. cpp:function:: Certificate_Status_Code result() const
|
|
|
|
Returns the 'worst' error that occurred during validation. For
|
|
instance, we do not want an expired certificate with an invalid
|
|
signature to be reported to the user as being simply expired (a
|
|
relatively innocuous and common error) when the signature isn't
|
|
even valid.
|
|
|
|
.. cpp:function:: const std::vector<std::set<Certificate_Status_Code>>& all_statuses() const
|
|
|
|
For each certificate in the chain, returns a set of status which
|
|
indicate all errors which occurred during validation. This is
|
|
primarily useful for diagnostic purposes.
|
|
|
|
.. cpp:function:: std::set<std::string> trusted_hashes() const
|
|
|
|
Returns the set of all cryptographic hash functions which are
|
|
implicitly trusted for this validation to be correct.
|
|
|
|
|
|
A ``Path_Validation_Restrictions`` is passed to the path
|
|
validator and specifies restrictions and options for the validation
|
|
step. The two constructors are:
|
|
|
|
.. cpp:function:: Path_Validation_Restrictions(bool require_rev, \
|
|
size_t minimum_key_strength, \
|
|
bool ocsp_all_intermediates, \
|
|
const std::set<std::string>& trusted_hashes)
|
|
|
|
If `require_rev` is true, then any path without revocation
|
|
information (CRL or OCSP check) is rejected with the code
|
|
`NO_REVOCATION_DATA`. The `minimum_key_strength` parameter
|
|
specifies the minimum strength of public key signature we will
|
|
accept is. The set of hash names `trusted_hashes` indicates which
|
|
hash functions we'll accept for cryptographic signatures. Any
|
|
untrusted hash will cause the error case `UNTRUSTED_HASH`.
|
|
|
|
.. cpp:function:: Path_Validation_Restrictions(bool require_rev = false, \
|
|
size_t minimum_key_strength = 80, \
|
|
bool ocsp_all_intermediates = false)
|
|
|
|
A variant of the above with some convenient defaults. The current
|
|
default `minimum_key_strength` of 80 roughly corresponds to 1024
|
|
bit RSA. The set of trusted hashes is set to all SHA-2 variants,
|
|
and, if `minimum_key_strength` is less than or equal to 80, then
|
|
SHA-1 signatures will also be accepted.
|
|
|
|
Creating New Certificates
|
|
---------------------------------
|
|
|
|
A CA is represented by the type ``X509_CA``, which can be found in
|
|
``x509_ca.h``. A CA always needs its own certificate, which can either
|
|
be a self-signed certificate (see below on how to create one) or one
|
|
issued by another CA (see the section on PKCS #10 requests). Creating
|
|
a CA object is done by the following constructor:
|
|
|
|
.. cpp:function:: X509_CA::X509_CA(const X509_Certificate& cert, \
|
|
const Private_Key& key, \
|
|
const std::string& hash_fn, \
|
|
RandomNumberGenerator& rng)
|
|
|
|
The private ``key`` is the private key corresponding to the public key in the
|
|
CA's certificate. ``hash_fn`` is the name of the hash function to use
|
|
for signing, e.g., `SHA-256`. ``rng`` is queried for random during signing.
|
|
|
|
There is an alternative constructor that lets you set additional options, namely
|
|
the padding scheme that will be used by the X509_CA object to sign certificates
|
|
and certificate revocation lists. If the padding is not set explicitly, the CA
|
|
will use some default. The only time you need this alternate interface is
|
|
for creating RSA-PSS certificates.
|
|
|
|
.. cpp:function:: X509_CA::X509_CA(const X509_Certificate& cert, \
|
|
const Private_Key& key, \
|
|
const std::string& hash_fn, \
|
|
const std::string& padding_fn, \
|
|
RandomNumberGenerator& rng)
|
|
|
|
Requests for new certificates are supplied to a CA in the form of PKCS
|
|
#10 certificate requests (called a ``PKCS10_Request`` object in
|
|
Botan). These are decoded in a similar manner to
|
|
certificates/CRLs/etc. A request is vetted by humans (who somehow
|
|
verify that the name in the request corresponds to the name of the
|
|
entity who requested it), and then signed by a CA key, generating a
|
|
new certificate:
|
|
|
|
.. cpp:function:: X509_Certificate \
|
|
X509_CA::sign_request(const PKCS10_Request& req, \
|
|
RandomNumberGenerator& rng, \
|
|
const X509_Time& not_before, \
|
|
const X509_Time& not_after)
|
|
|
|
If you need more control over the signing process, you can use the methods
|
|
|
|
.. cpp:function:: static X509_Certificate X509_CA::make_cert(PK_Signer& signer, \
|
|
RandomNumberGenerator& rng, \
|
|
const BigInt& serial_number, \
|
|
const AlgorithmIdentifier& sig_algo, \
|
|
const std::vector<uint8_t>& pub_key, \
|
|
const X509_Time& not_before, \
|
|
const X509_Time& not_after, \
|
|
const X509_DN& issuer_dn, \
|
|
const X509_DN& subject_dn, \
|
|
const Extensions& extensions)
|
|
|
|
.. cpp:function:: static Extensions X509_CA::choose_extensions(const PKCS10_Request& req, \
|
|
const X509_Certificate& ca_certificate, \
|
|
const std::string& hash_fn)
|
|
|
|
Returns the extensions that would be created by sign_request if it was used.
|
|
You can call this and then modify the extensions list before invoking
|
|
:cpp:func:`X509_CA::make_cert`
|
|
|
|
Generating CRLs
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
As mentioned previously, the ability to process CRLs is highly
|
|
important in many PKI systems. In fact, according to strict X.509
|
|
rules, you must not validate any certificate if the appropriate CRLs
|
|
are not available (though hardly any systems are that strict). In any
|
|
case, a CA should have a valid CRL available at all times.
|
|
|
|
Of course, you might be wondering what to do if no certificates have
|
|
been revoked. Never fear; empty CRLs, which revoke nothing at all, can
|
|
be issued. To generate a new, empty CRL, just call
|
|
|
|
.. cpp:function:: X509_CRL X509_CA::new_crl(RandomNumberGenerator& rng, \
|
|
uint32_t next_update = 0)
|
|
|
|
This function will return a new, empty CRL. The ``next_update`` parameter is
|
|
the number of seconds before the CRL expires. If it is set to the (default)
|
|
value of zero, then a reasonable default (currently 7 days) will be used.
|
|
|
|
On the other hand, you may have issued a CRL before. In that case, you will
|
|
want to issue a new CRL that contains all previously revoked
|
|
certificates, along with any new ones. This is done by calling
|
|
|
|
.. cpp:function:: X509_CRL X509_CA::update_crl(const X509_CRL& last_crl, \
|
|
std::vector<CRL_Entry> new_entries, RandomNumberGenerator& rng, \
|
|
size_t next_update = 0)
|
|
|
|
Where ``last_crl`` is the last CRL this CA issued, and
|
|
``new_entries`` is a list of any newly revoked certificates. The
|
|
function returns a new ``X509_CRL`` to make available for
|
|
clients.
|
|
|
|
The ``CRL_Entry`` type is a structure that contains, at a minimum, the serial
|
|
number of the revoked certificate. As serial numbers are never repeated, the
|
|
pairing of an issuer and a serial number (should) distinctly identify any
|
|
certificate. In this case, we represent the serial number as a
|
|
``secure_vector<uint8_t>`` called ``serial``. There are two additional (optional)
|
|
values, an enumeration called ``CRL_Code`` that specifies the reason for
|
|
revocation (``reason``), and an object that represents the time that the
|
|
certificate became invalid (if this information is known).
|
|
|
|
If you wish to remove an old entry from the CRL, insert a new entry for the
|
|
same cert, with a ``reason`` code of ``REMOVE_FROM_CRL``. For example, if a
|
|
revoked certificate has expired 'normally', there is no reason to continue to
|
|
explicitly revoke it, since clients will reject the cert as expired in any
|
|
case.
|
|
|
|
Self-Signed Certificates
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
Generating a new self-signed certificate can often be useful, for
|
|
example when setting up a new root CA, or for use in specialized
|
|
protocols. The library provides a utility function for this:
|
|
|
|
.. cpp:function:: X509_Certificate create_self_signed_cert( \
|
|
const X509_Cert_Options& opts, const Private_Key& key, \
|
|
const std::string& hash_fn, RandomNumberGenerator& rng)
|
|
|
|
Where ``key`` is the private key you wish to use (the public key,
|
|
used in the certificate itself is extracted from the private key),
|
|
and ``opts`` is an structure that has various bits of information
|
|
that will be used in creating the certificate (this structure, and
|
|
its use, is discussed below).
|
|
|
|
Creating PKCS #10 Requests
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
Also in ``x509self.h``, there is a function for generating new PKCS #10
|
|
certificate requests:
|
|
|
|
.. cpp:function:: PKCS10_Request create_cert_req( \
|
|
const X509_Cert_Options& opts, const Private_Key& key, \
|
|
const std::string& hash_fn, RandomNumberGenerator& rng)
|
|
|
|
This function acts quite similarly to
|
|
:cpp:func:`create_self_signed_cert`, except it instead returns a PKCS
|
|
#10 certificate request. After creating it, one would typically
|
|
transmit it to a CA, who signs it and returns a freshly minted X.509
|
|
certificate.
|
|
|
|
.. cpp:function:: PKCS10_Request PKCS10_Request::create(const Private_Key& key, \
|
|
const X509_DN& subject_dn, \
|
|
const Extensions& extensions, \
|
|
const std::string& hash_fn, \
|
|
RandomNumberGenerator& rng, \
|
|
const std::string& padding_scheme = "", \
|
|
const std::string& challenge = "")
|
|
|
|
This function (added in 2.5) is similar to ``create_cert_req`` but allows
|
|
specifying all the parameters directly. In fact ``create_cert_req`` just
|
|
creates the DN and extensions from the options, then uses this call to
|
|
actually create the ``PKCS10_Request`` object.
|
|
|
|
|
|
Certificate Options
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
What is this ``X509_Cert_Options`` thing we've been passing around?
|
|
It's a class representing a bunch of information that will end up
|
|
being stored into the certificate. This information comes in 3 major
|
|
flavors: information about the subject (CA or end-user), the validity
|
|
period of the certificate, and restrictions on the usage of the
|
|
certificate. For special cases, you can also add custom X.509v3
|
|
extensions.
|
|
|
|
First and foremost is a number of ``std::string`` members, which
|
|
contains various bits of information about the user: ``common_name``,
|
|
``serial_number``, ``country``, ``organization``, ``org_unit``,
|
|
``locality``, ``state``, ``email``, ``dns_name``, and ``uri``. As many
|
|
of these as possible should be filled it (especially an email
|
|
address), though the only required ones are ``common_name`` and
|
|
``country``.
|
|
|
|
Additionally there are a small selection of ``std::vector<std::string>``
|
|
members, which allow space for repeating elements:
|
|
``more_org_units`` and ``more_dns``.
|
|
|
|
There is another value that is only useful when creating a PKCS #10
|
|
request, which is called ``challenge``. This is a challenge password,
|
|
which you can later use to request certificate revocation (*if* the CA
|
|
supports doing revocations in this manner).
|
|
|
|
Then there is the validity period; these are set with ``not_before``
|
|
and ``not_after``. Both of these functions also take a
|
|
``std::string``, which specifies when the certificate should start
|
|
being valid, and when it should stop being valid. If you don't set the
|
|
starting validity period, it will automatically choose the current
|
|
time. If you don't set the ending time, it will choose the starting
|
|
time plus a default time period. The arguments to these functions
|
|
specify the time in the following format: "2002/11/27 1:50:14". The
|
|
time is in 24-hour format, and the date is encoded as
|
|
year/month/day. The date must be specified, but you can omit the time
|
|
or trailing parts of it, for example "2002/11/27 1:50" or
|
|
"2002/11/27".
|
|
|
|
Third, you can set constraints on a key. The one you're mostly likely
|
|
to want to use is to create (or request) a CA certificate, which can
|
|
be done by calling the member function ``CA_key``. This should only be
|
|
used when needed.
|
|
|
|
Moreover, you can specify the padding scheme to be used when digital signatures
|
|
are computed by calling function ``set_padding_scheme`` with a string
|
|
representing the padding scheme. This way, you can control the padding scheme
|
|
for self-signed certificates and PKCS #10 requests. The padding scheme used by
|
|
a CA when building a certificate or a certificate revocation list can be set in
|
|
the ``X509_CA`` constructor. The supported padding schemes can be found in
|
|
src/lib/pubkey/padding.cpp. Some alternative names for the padding schemes are
|
|
understood, as well.
|
|
|
|
Other constraints can be set by calling the member functions
|
|
``add_constraints`` and ``add_ex_constraints``. The first takes a
|
|
``Key_Constraints`` value, and replaces any previously set value. If
|
|
no value is set, then the certificate key is marked as being valid for
|
|
any usage. You can set it to any of the following (for more than one
|
|
usage, OR them together): ``DigitalSignature``, ``NonRepudiation``,
|
|
``KeyEncipherment``, ``DataEncipherment``, ``KeyAgreement``,
|
|
``KeyCertSign``, ``CrlSign``, ``EncipherOnly``, or ``DecipherOnly``.
|
|
Many of these have quite special semantics, so you should either
|
|
consult the appropriate standards document (such as RFC 5280), or just
|
|
not call ``add_constraints``, in which case the appropriate values
|
|
will be chosen for you based on the key type.
|
|
|
|
The second function, ``add_ex_constraints``, allows you to specify an
|
|
OID that has some meaning with regards to restricting the key to
|
|
particular usages. You can, if you wish, specify any OID you like, but
|
|
there is a set of standard ones that other applications will be able
|
|
to understand. These are the ones specified by the PKIX standard, and
|
|
are named "PKIX.ServerAuth" (for TLS server authentication),
|
|
"PKIX.ClientAuth" (for TLS client authentication), "PKIX.CodeSigning",
|
|
"PKIX.EmailProtection" (most likely for use with S/MIME),
|
|
"PKIX.IPsecUser", "PKIX.IPsecTunnel", "PKIX.IPsecEndSystem", and
|
|
"PKIX.TimeStamping". You can call "add_ex_constraints" any number of
|
|
times - each new OID will be added to the list to include in the
|
|
certificate.
|
|
|
|
Lastly, you can add any X.509v3 extensions in the `extensions` member, which is
|
|
useful if you want to encode a custom extension, or encode an extension in a way
|
|
differently from how Botan defaults.
|
|
|
|
OCSP Requests
|
|
----------------------------------------
|
|
|
|
A client makes an OCSP request to what is termed an 'OCSP responder'. This
|
|
responder returns a signed response attesting that the certificate in question
|
|
has not been revoked. The most recent OCSP specification is as of this
|
|
writing :rfc:`6960`.
|
|
|
|
Normally OCSP validation happens automatically as part of X.509 certificate
|
|
validation, as long as OCSP is enabled (by setting a non-zero ``ocsp_timeout``
|
|
in the call to ``x509_path_validate``, or for TLS by implementing the related
|
|
``tls_verify_cert_chain_ocsp_timeout`` callback and returning a non-zero value
|
|
from that). So most applications should not need to directly manipulate OCSP
|
|
request and response objects.
|
|
|
|
For those that do, the primary ocsp interface is in ``ocsp.h``. First a request
|
|
must be formed, using information contained in the subject certificate and in
|
|
the subject's issuing certificate.
|
|
|
|
.. cpp:class:: OCSP::Request
|
|
|
|
.. cpp:function:: OCSP::Request(const X509_Certificate& issuer_cert, \
|
|
const BigInt& subject_serial)
|
|
|
|
Create a new OCSP request
|
|
|
|
.. cpp:function:: OCSP::Request(const X509_Certificate& issuer_cert, \
|
|
const X509_Certificate& subject_cert)
|
|
|
|
Variant of the above, using serial number from ``subject_cert``.
|
|
|
|
.. cpp:function:: std::vector<uint8_t> BER_encode() const
|
|
|
|
Encode the current OCSP request as a binary string.
|
|
|
|
.. cpp:function:: std::string base64_encode() const
|
|
|
|
Encode the current OCSP request as a base64 string.
|
|
|
|
Then the response is parsed and validated, and if valid, can be consulted
|
|
for certificate status information.
|
|
|
|
.. cpp:class:: OCSP::Response
|
|
|
|
.. cpp:function:: OCSP::Response(const uint8_t response_bits[], size_t response_bits_len)
|
|
|
|
Attempts to parse ``response_bits`` as an OCSP response. Throws an
|
|
exception if parsing fails. Note that this does not verify that the OCSP
|
|
response is valid (ie that the signature is correct), merely that the
|
|
ASN.1 structure matches an OCSP response.
|
|
|
|
.. cpp:function:: Certificate_Status_Code check_signature( \
|
|
const std::vector<Certificate_Store*>& trust_roots, \
|
|
const std::vector<X509_Certificate>& cert_path = const std::vector<X509_Certificate>()) const
|
|
|
|
Find the issuing certificate of the OCSP response, and check the signature.
|
|
|
|
If possible, pass the full certificate path being validated in
|
|
the optional ``cert_path`` argument: this additional information
|
|
helps locate the OCSP signer's certificate in some cases. If this
|
|
does not return ``Certificate_Status_Code::OCSP_SIGNATURE_OK``,
|
|
then the request must not be be used further.
|
|
|
|
.. cpp:function:: Certificate_Status_Code verify_signature(const X509_Certificate& issuing_cert) const
|
|
|
|
If the certificate that issued the OCSP response is already known (eg,
|
|
because in some specific application all the OCSP responses will always
|
|
be signed by a single trusted issuer whose cert is baked into the code)
|
|
this provides an alternate version of `check_signature`.
|
|
|
|
.. cpp:function:: Certificate_Status_Code status_for(const X509_Certificate& issuer, \
|
|
const X509_Certificate& subject, \
|
|
std::chrono::system_clock::time_point ref_time = std::chrono::system_clock::now()) const
|
|
|
|
Assuming the signature is valid, returns the status for the subject certificate.
|
|
Make sure to get the ordering of the issuer and subject certificates correct.
|
|
|
|
The ``ref_time`` is normally just the system clock, but can be used if
|
|
validation against some other reference time is desired (such as for
|
|
testing, to verify an old previously valid OCSP response, or to use an
|
|
alternate time source such as the Roughtime protocol instead of the local
|
|
client system clock).
|
|
|
|
.. cpp:function:: const X509_Time& produced_at() const
|
|
|
|
Return the time this OCSP response was (claimed to be) produced at.
|
|
|
|
.. cpp:function:: const X509_DN& signer_name() const
|
|
|
|
Return the distinguished name of the signer. This is used to help
|
|
find the issuing certificate.
|
|
|
|
This field is optional in OCSP responses, and may not be set.
|
|
|
|
.. cpp:function:: const std::vector<uint8_t>& signer_key_hash() const
|
|
|
|
Return the SHA-1 hash of the public key of the signer. This is used to
|
|
help find the issuing certificate. The ``Certificate_Store`` API
|
|
``find_cert_by_pubkey_sha1`` can search on this value.
|
|
|
|
This field is optional in OCSP responses, and may not be set.
|
|
|
|
.. cpp:function:: const std::vector<uint8_t>& raw_bits() const
|
|
|
|
Return the entire raw ASN.1 blob (for debugging or specialized decoding needs)
|
|
|
|
One common way of making OCSP requests is via HTTP, see :rfc:`2560`
|
|
Appendix A for details. A basic implementation of this is the function
|
|
``online_check``, which is available as long as the ``http_util`` module
|
|
was compiled in; check by testing for the macro ``BOTAN_HAS_HTTP_UTIL``.
|
|
|
|
.. cpp:function:: OCSP::Response online_check(const X509_Certificate& issuer, \
|
|
const BigInt& subject_serial, \
|
|
const std::string& ocsp_responder, \
|
|
const Certificate_Store* trusted_roots)
|
|
|
|
Assemble a OCSP request for serial number ``subject_serial`` and attempt to request
|
|
it to responder at URI ``ocsp_responder`` over a new HTTP socket, parses and returns
|
|
the response. If trusted_roots is not null, then the response is additionally
|
|
validated using OCSP response API ``check_signature``. Otherwise, this call must be
|
|
performed later by the application.
|
|
|
|
.. cpp:function:: OCSP::Response online_check(const X509_Certificate& issuer, \
|
|
const X509_Certificate& subject, \
|
|
const Certificate_Store* trusted_roots)
|
|
|
|
Variant of the above but uses serial number and OCSP responder URI from ``subject``.
|